The GraphQL specification doesn't dictates which transport must be used in order to execute operations. In fact, GraphQL is transport agnostic, so implementors can choose which protocol makes more sense for each use case.
Generally, query
and mutation
are carried via HTTP, while subscription
via WebSocket: this is the default behavior in mercurius
and many other server implementations. However, query
and mutation
can also be sent through WebSocket.
As WebSocket is a generic and bidirectional way to send messages, we need to agree about what each message means: this is defined by the subprotocol.
The GraphQL over WebSocket Protocol (i.e. the WebSocket sub-protocol) used by default is called graphql-transport-ws
and it's defined here:
⚠️ The subprotocol originally defined by Apollo'ssubscriptions-transport-ws
library is also supported. However, that library is UNMAINTAINED so it's not recommended to be used: basically deprecated. More info here.
You should be able to use any major GraphQL client library in order to send operations via WebSocket (e.g. graphql-ws
, graphql-hooks
, apollo
, urql
…). Depending on which client you use, you have built in support or you may need to use some plugins or middleware.
The extensions
field is reserved for things that implementors want to add on top of the spec.
This is the structure allowed on each WS message:
export interface OperationMessage {
payload?: any;
id?: string;
type: string;
extensions?: Array<OperationExtension>;
}
export interface OperationExtension {
type: string;
payload?: any;
}
In order to achieve gateway-to-service communication and handle connection_init
per client, an extension is used on the protocol for server-to-server communication. See mercurius-js#268 for more details about the original issue and the actual implemented solution.
Gateway uses this extension to share the connection_init
payload with a service when the connection is already established between gateway and services.
export interface ConnectionInitExtension extends OperationExtension {
type: string;
payload?: Object;
}
type: String
: 'connectionInit'payload: Object
: optional parameters that the client specifies in connectionParams