Primus-GraphQL is a flexible client and server library that can be used to power realtime GraphQL applications. It is similar to Express-GraphQL but with support for Relay and Subscriptions!
This module is a Primus plugin. Primus is a robust realtime abstraction layer that allows you to use WebSockets, Socket.io, Engine.io, SockJS, or any transport-layer. Primus powers sending and receiving data on both the client and the server. Primus-GraphQL makes it easy to send and handle GraphQL queries, mutations, and subscriptions.
npm i --save primus-graphql
npm i --save rxjs # peer dependency (server/client)
npm i --save graphql # peer dependency (server)
npm i --save relay-runtime # optional peer dependency (if using relay in client)
Server Example:
import {
GraphQLSchema,
GraphQLString,
GraphQLObjectType,
} from 'graphql'
import primus from 'primus'
import primusGraphQL from 'primus-graphql'
const UserType = new GraphQLObjectType({
name: 'User',
description: 'user',
fields: {
id: { type: GraphQLString },
name: { type: GraphQLString }
}
})
const Query = new GraphQLObjectType({
name: 'Query',
description: 'Root query',
fields: {
user: {
type: UserType,
args: {},
resolve: () => {
return {
id: 1,
name: 'name'
}
}
}
}
})
const schema = new GraphQLSchema({
query: Query
})
const server = /* your http server */
const primus = new Primus(server, {
transport: /* transport */,
parser: 'json'
})
primus.use('graphql', primusGraphQL({
// `schema` is required
schema: schema,
// Optional options
context: function (spark) {
return spark
},
rootValue: null,
formatError: function (err) {
return {
message: err.message
}
},
validationRules: [/* additional validation rules */]
}))
Client Example:
const client = new Primus()
const query = 'query { user { id, name } }'
// promise api
client.graphql(query).then(function (data) {
if (data.errors) {
console.error(data.errors)
return
}
console.log(data)
/* see hardcoded server example below
{
data: {
user: {
id: 1,
name: 'name'
}
}
}
*/
})
// callback api
client.graphql(query, function (err, data) {
if (err) {
console.error(err)
return
}
if (data.errors) {
console.error(data.errors)
return
}
console.log(data)
/* see hardcoded server example below
{
data: {
user: {
id: 1,
name: 'name'
}
}
}
*/
})
The primusGraphQL
plugin function accepts the following options:
-
schema
: AGraphQLSchema
instance from [graphql-js
][]. Aschema
must be provided. -
context
: Optional. A value to pass as thecontext
to thegraphql()
function from [graphql-js
][]. If a function is used it will be invoke w/spark
, and must return thecontext
. -
rootValue
: Optional. A value to pass as therootValue
to thegraphql()
function from [graphql-js
][]. If a function is used it will be invoke w/spark
, and must return therootValue
. -
formatError
: Optional. An optional function which will be used to format any errors produced by fulfilling a GraphQL operation. If no function is provided, GraphQL's default spec-compliant [formatError
][] function will be used. -
validationRules
: Optional. Additional validation rules queries must satisfy in addition to those defined by the GraphQL spec.
The PrimusRelayNetwork
class accepts the following options:
timeout
: The max timeout for any graphql query or mutation.retry
: Exponential backoff settings for retryable query, mutation, or subscription errors.retry.maxTimeout
: The max timeout to wait before retrying.retry.minTimeout
: The min timeout to wait before retrying.retry.factor
: The factor in which to increase the retry timeout.retry.retries
: The max number of retries to attempt.
If primus disconnects and reconnects, any graphql subscriptions that were not disposed will resend the same query and resume. If this behavior is undesired dispose the subscription on primus 'disconnect'.
import React from 'react'
import ReactDom from 'react-dom'
import PrimusRelayNetwork from 'primus-graphql/relay-network'
import { QueryRenderer, graphql } from 'react-relay';
import { Environment, RecordSource, Store } from 'relay-runtime';
const primus = new Primus()
const network = new PrimusRelayNetwork(primus, {
// default options:
timeout: 15000,
retry: {
minTimeout: 1000,
maxTimeout: 3000,
factor: 3,
retries: 2
}
})
const environment = new Environment({
network: network,
store: new Store(new RecordSource()),
});
ReactDOM.render(
<QueryRenderer
environment={environment}
query={graphql`
query appQuery {
viewer {
...App_viewer
}
}
`}
render={({error, props}) => {
if (error) {
return <div>{error.message}</div>
}
if (!props) {
return <div>Loading</div>
}
return <div>{`viewer: ${JSON.stringify(props.viewer)}`}</div>
}}
/>,
document.getElementById('root'),
)
Check out the end-to-end tests here: browser_tests/primus-graphql.e2e.js
Thank you to the contributors of Primus, GraphQL, and Relay!
MIT