Package Exports
- subscriptions-transport-ws
- subscriptions-transport-ws/dist/adapters/subscription-manager
- subscriptions-transport-ws/dist/client
- subscriptions-transport-ws/dist/defaults
- subscriptions-transport-ws/dist/helpers
- subscriptions-transport-ws/dist/legacy/define-deprecation-function-wrapper
- subscriptions-transport-ws/dist/legacy/parse-legacy-protocol
- subscriptions-transport-ws/dist/message-types
- subscriptions-transport-ws/dist/protocol
- subscriptions-transport-ws/dist/utils/empty-iterable
- subscriptions-transport-ws/dist/utils/is-subscriptions
- subscriptions-transport-ws/dist/utils/promise-to-iterable
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (subscriptions-transport-ws) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
subscriptions-transport-ws
(Work in progress!)
A GraphQL WebSocket server and client to facilitate GraphQL queries, mutations and subscriptions over WebSocket.
subscriptions-transport-wsis an extension for GraphQL, and you can use it with any GraphQL client and server (not only Apollo).
See GitHunt-API and GitHunt-React for an example server and client integration.
Getting Started
Start by installing the package, using Yarn or NPM.
Using Yarn:
$ yarn add subscriptions-transport-ws
Or, using NPM:
$ npm install --save subscriptions-transport-wsNote that you need to use this package on both GraphQL client and server.
This command also installs this package's dependencies, including
graphql-subscriptions.
Server
Starting with the server, create a new simple PubSub instance. We will later use this PubSub to publish and subscribe to data changes.
import { PubSub } from 'graphql-subscriptions';
export const pubsub = new PubSub();Now, create SubscriptionServer instance, with your GraphQL schema, execute and subscribe (from graphql-js package):
import { createServer } from 'http';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import { execute, subscribe } from 'graphql';
import { schema } from './my-schema';
const WS_PORT = 5000;
// Create WebSocket listener server
const websocketServer = createServer((request, response) => {
response.writeHead(404);
response.end();
});
// Bind it to port and start listening
websocketServer.listen(WS_PORT, () => console.log(
`Websocket Server is now running on http://localhost:${WS_PORT}`
));
const subscriptionServer = SubscriptionServer.create(
{
schema,
execute,
subscribe,
},
{
server: websocketServer,
path: '/graphql',
},
);Creating Your Subscriptions
Please refer to graphql-subscriptions documentation for how to create your GraphQL subscriptions, and how to publish data.
Client (browser)
When using this package for client side, you can choose either use HTTP request for Queries and Mutation and use the WebSocket for subscriptions only, or create a full transport that handles all type of GraphQL operations over the socket.
Full WebSocket Transport
To start with a full WebSocket transport, that handles all types of GraphQL operations, import and create an instance of SubscriptionClient.
Then, create your ApolloClient instance and use the SubscriptionsClient instance as network interface:
import { SubscriptionClient } from 'subscriptions-transport-ws';
import ApolloClient from 'apollo-client';
const GRAPHQL_ENDPOINT = 'ws://localhost:3000/graphql';
const client = new SubscriptionClient(GRAPHQL_ENDPOINT, {
reconnect: true,
});
const apolloClient = new ApolloClient({
networkInterface: client,
});
Hybrid WebSocket Transport
To start with a full WebSocket transport, that handles only subscriptions over WebSocket, create your SubscriptionClient and a regular HTTP network interface, then extend your network interface to use the WebSocket client for GraphQL subscriptions:
import {SubscriptionClient, addGraphQLSubscriptions} from 'subscriptions-transport-ws';
import ApolloClient, {createNetworkInterface} from 'apollo-client';
// Create regular NetworkInterface by using apollo-client's API:
const networkInterface = createNetworkInterface({
uri: 'http://localhost:3000' // Your GraphQL endpoint
});
// Create WebSocket client
const wsClient = new SubscriptionClient(`ws://localhost:5000/`, {
reconnect: true,
connectionParams: {
// Pass any arguments you want for initialization
}
});
// Extend the network interface with the WebSocket
const networkInterfaceWithSubscriptions = addGraphQLSubscriptions(
networkInterface,
wsClient
);
// Finally, create your ApolloClient instance with the modified network interface
const apolloClient = new ApolloClient({
networkInterface: networkInterfaceWithSubscriptions
});Now, when you want to use subscriptions in client side, use your ApolloClient instance, with subscribe or subscribeToMore (according to your apollo-client usage):
apolloClient.subscribeToMore({
document: gql`
subscription onNewItem {
newItemCreated {
id
}
}`,
variables: {},
updateQuery: (prev, {subscriptionData}) => {
// Modify your store and return new state with the new arrived data
}
});If you don't use any package/modules loader, you can still use this package, by using unpkg service, and get the client side package from:
https://unpkg.com/subscriptions-transport-ws@VERSION/browser/client.jsReplace VERSION with the latest version of the package.
Use it with GraphiQL
You can use this package's power with GraphiQL, and subscribe to live-data stream inside GraphiQL.
If you are using the latest version of graphql-server flavors (graphql-server-express, graphql-server-koa, etc...), you already can use it! Make sure to specify subscriptionsEndpoint in GraphiQL configuration, and that's it!
For example, graphql-server-express users need to add the following:
app.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql',
subscriptionsEndpoint: `YOUR_SUBSCRIPTION_ENDPOINT_HERE`,
}));If you are using older version, or another GraphQL server, start by modifying GraphiQL static HTML, and add this package and it's fetcher from CDN:
<script src="//unpkg.com/subscriptions-transport-ws@0.5.4/browser/client.js"></script>
<script src="//unpkg.com/graphiql-subscriptions-fetcher@0.0.2/browser/client.js"></script>Then, create SubscriptionClient and define the fetcher:
let subscriptionsClient = new window.SubscriptionsTransportWs.SubscriptionClient('SUBSCRIPTION_WS_URL_HERE', {
reconnect: true
});
let myCustomFetcher = window.GraphiQLSubscriptionsFetcher.graphQLFetcher(subscriptionsClient, graphQLFetcher);
graphQLFetcheris the default fetcher, and we use it as fallback for non-subscription GraphQL operations.
And replace your GraphiQL creation logic to use the new fetcher:
ReactDOM.render(
React.createElement(GraphiQL, {
fetcher: myCustomFetcher, // <-- here
onEditQuery: onEditQuery,
onEditVariables: onEditVariables,
onEditOperationName: onEditOperationName,
query: ${safeSerialize(queryString)},
response: ${safeSerialize(resultString)},
variables: ${safeSerialize(variablesString)},
operationName: ${safeSerialize(operationName)},
}),
document.body
);API Docs
SubscriptionClient
Constructor(url, options, connectionCallback)
url: string: url that the client will connect to, starts withws://orwss://options?: Object: optional, object to modify default client behaviortimeout?: number: how long the client should wait in ms for a keep-alive message from the server (default 10000 ms), this parameter is ignored if the server does not send keep-alive messages. This will also be used to calculate the max connection time per connect/reconnectlazy?: boolean: use to set lazy mode - connects only when first subscription created, and delay the socket initializationconnectionParams?: Object | Function: object that will be available as first argument ofonConnect(in server side), if passed a function - it will call it and send the return valuereconnect?: boolean: automatic reconnect in case of connection errorreconnectionAttempts?: number: how much reconnect attemptsconnectionCallback?: (error) => {}: optional, callback that called after the first init message, with the error (if there is one)
webSocketImpl?: Object- optional, WebSocket implementation. use this when your environment does not have a built-in native WebSocket (for example, with NodeJS client)
Methods
subscribe(options, handler) => number: returns the operation id that identifies the operation
options: {SubscriptionOptions}query: string: GraphQL subscriptionvariables: Object: GraphQL subscription variablesoperationName: string: operation name of the subscriptioncontext: Object: use to override context for a specific call
handler: (errors: Error[], result?: any) => void: function to handle any errors and results from the subscription response
unsubscribe(id) => void - unsubscribes from a specific subscription
id: string: the subscription ID of the subscription to unsubscribe from
unsubscribeAll() => void - unsubscribes from all active subscriptions.
on(eventName, callback, thisContext) => Function
eventName: string: the name of the event, available events are:connecting,connected,reconnecting,reconnectedanddisconnectedcallback: Function: function to be called when websocket connects and initialized.thisContext: any:thiscontext to use when calling the callback function.- => Returns an
offmethod to cancel the event subscription.
onConnected(callback, thisContext) => Function - shorthand for .on('connected', ...)
callback: Function: function to be called when websocket connects and initialized, after ACK message returned from the serverthisContext: any:thiscontext to use when calling the callback function.- => Returns an
offmethod to cancel the event subscription.
onReconnected(callback, thisContext) => Function - shorthand for .on('reconnected', ...)
callback: Function: function to be called when websocket reconnects and initialized, after ACK message returned from the serverthisContext: any:thiscontext to use when calling the callback function.- => Returns an
offmethod to cancel the event subscription.
onConnecting(callback, thisContext) => Function - shorthand for .on('connecting', ...)
callback: Function: function to be called when websocket starts it's connectionthisContext: any:thiscontext to use when calling the callback function.- => Returns an
offmethod to cancel the event subscription.
onReconnecting(callback, thisContext) => Function - shorthand for .on('reconnecting', ...)
callback: Function: function to be called when websocket starts it's reconnectionthisContext: any:thiscontext to use when calling the callback function.- => Returns an
offmethod to cancel the event subscription.
onDisconnected(callback, thisContext) => Function - shorthand for .on('disconnected', ...)
callback: Function: function to be called when websocket disconnected.thisContext: any:thiscontext to use when calling the callback function.- => Returns an
offmethod to cancel the event subscription.
query(options: OperationOptions) => Promise<ExecutionResult> : Executes GraphQL operation over the WebSocket
options: OperationOptions:query: string- GraphQL operation as string or parsed GraphQL document nodevariables?: Object- Object with GraphQL variablesoperationName?: string- GraphQL operation namecontext?: any- Execution context for the operation
close() => void - closes the WebSocket connection manually, and ignores reconnect logic if it was set to true.
use(middlewares: MiddlewareInterface[]) => SubscriptionClient - adds middleware to modify OperationOptions per each request
middlewares: MiddlewareInterface[]- Array contains list of middlewares (implementedapplyMiddlewaremethod) implementation, theSubscriptionClientwill use the middlewares to modifyOperationOptionsfor every operation
status: number : returns the current socket's readyState
@deprecated onConnect(callback, thisContext) => Function - shorthand for .on('connect', ...)
callback: Function: function to be called when websocket connects and initialized.thisContext: any:thiscontext to use when calling the callback function.- => Returns an
offmethod to cancel the event subscription.
@deprecated onReconnect(callback, thisContext) => Function - shorthand for .on('reconnect', ...)
callback: Function: function to be called when websocket re-connects and initialized.thisContext: any:thiscontext to use when calling the callback function.- => Returns an
offmethod to cancel the event subscription.
@deprecated onDisconnect(callback, thisContext) => Function - shorthand for .on('disconnect', ...)
callback: Function: function to be called when websocket disconnects.thisContext: any:thiscontext to use when calling the callback function.- => Returns an
offmethod to cancel the event subscription.
Client-side helpers
addGraphQLSubscriptions(networkInterface, wsClient) => void
networkInterface: any- network interface to extend withsubscribeandunsubscribemethods.wsClient: SubscriptionClient- network interface to extend withsubscribeandunsubscribemethods.
A quick way to add the subscribe and unsubscribe functions to the network interface, when using Hybrid socket mode.
SubscriptionServer
Constructor(options, socketOptions)
options: {ServerOptions}rootValue?: any: Root value to use when executing GraphQL root operationsschema?: GraphQLSchema: GraphQL schema objectexecute?: (schema, document, rootValue, contextValue, variableValues, operationName) => Promise<ExecutionResult> | AsyncIterator<ExecutionResult>: GraphQLexecutefunction, provide the default one fromgraphqlpackage. Return value ofAsyncItratoris also valid since this package also support reactiveexecutemethods.subscribe?: (schema, document, rootValue, contextValue, variableValues, operationName) => AsyncIterator<ExecutionResult>: GraphQLsubscribefunction, provide the default one fromgraphqlpackage.onOperation?: (message: SubscribeMessage, params: SubscriptionOptions, webSocket: WebSocket): optional method to create custom params that will be used when resolving this operationonOperationComplete?: (webSocket: WebSocket, opId: string): optional method that called when a GraphQL operation is done (for query and mutation it's immeditaly, and for subscriptions when unsubscribing)onConnect?: (connectionParams: Object, webSocket: WebSocket): optional method that called when a client connects to the socket, called with theconnectionParamsfrom the client, if the return value is an object, its elements will be added to the context. returnfalseor throw an exception to reject the connection. May return a Promise.onDisconnect?: (webSocket: WebSocket): optional method that called when a client disconnectskeepAlive?: number: optional interval in ms to sendKEEPALIVEmessages to all clients@deprecated
onSubscribe?: (message: SubscribeMessage, params: SubscriptionOptions, webSocket: WebSocket): optional method to create custom params that will be used when resolving this subscription@deprecated
onUnsubscribe?: (webSocket: WebSocket): optional method that called when a client unsubscribe@deprecated
subscriptionManager?: SubscriptionManager: support for old implementation usingSubscriptionsManagerfromgraphql-subscriptions- an alternative forgraphql's built-inexecuteandsubscribe.
socketOptions: {WebSocket.IServerOptions}: options to pass to the WebSocket object (full docs here)server?: HttpServer- existing HTTP server to use (use withouthost/port)host?: string- server hostport?: number- server portpath?: string- endpoint path
How it works?
- For GraphQL WebSocket protocol docs, click here
- This package also uses
AsyncIteratorinternally using iterall, for more information click here, or the proposal
The current version of this transport, also support a previous version of the protocol.