Skip to content

Commit

Permalink
feat(server): Define execution/subscription context in creation opt…
Browse files Browse the repository at this point in the history
…ions

Closes enisdenjo#13
  • Loading branch information
enisdenjo committed Sep 18, 2020
1 parent 6fbd47c commit 5b3d253
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 1 deletion.
10 changes: 10 additions & 0 deletions src/server.ts
Expand Up @@ -52,6 +52,14 @@ export interface ServerOptions {
* from the `onSubscribe` callback.
*/
schema?: GraphQLSchema;
/**
* A value which is provided to every resolver and holds
* important contextual information like the currently
* logged in user, or access to a database.
* Related operation context value will be injected to the
* `ExecutionArgs` BEFORE the `onSubscribe` callback.
*/
context?: SubscriptionArgs['contextValue'];
/**
* The GraphQL root fields or resolvers to go
* alongside the schema. Learn more about them
Expand Down Expand Up @@ -213,6 +221,7 @@ export function createServer(
): Server {
const {
schema,
context,
roots,
execute,
subscribe,
Expand Down Expand Up @@ -403,6 +412,7 @@ export function createServer(
}

let execArgsMaybeSchema: Optional<ExecutionArgs, 'schema'> = {
contextValue: context,
schema,
operationName: operation.operationName,
document,
Expand Down
8 changes: 8 additions & 0 deletions src/tests/fixtures/simple.ts
Expand Up @@ -33,6 +33,14 @@ export const schema = new GraphQLSchema({
subscription: new GraphQLObjectType({
name: 'Subscription',
fields: {
greetings: {
type: new GraphQLNonNull(GraphQLString),
subscribe: async function* () {
for (const hi of ['Hi', 'Bonjour', 'Hola', 'Ciao', 'Zdravo']) {
yield { greetings: hi };
}
},
},
becameHappy: {
type: personType,
args: {
Expand Down
74 changes: 73 additions & 1 deletion src/tests/server.ts
@@ -1,5 +1,5 @@
import WebSocket from 'ws';
import { parse, buildSchema } from 'graphql';
import { parse, buildSchema, execute, subscribe } from 'graphql';
import { GRAPHQL_TRANSPORT_WS_PROTOCOL } from '../protocol';
import { MessageType, parseMessage, stringifyMessage } from '../message';
import { startServer, url, schema, pubsub } from './fixtures/simple';
Expand Down Expand Up @@ -998,3 +998,75 @@ it('should use the provided roots as resolvers', async () => {
});
expect(nextFn).toBeCalledTimes(3);
});

it('should pass in the context value from the config', async () => {
const context = {};

const executeFn = jest.fn((args) => execute(args));
const subscribeFn = jest.fn((args) => subscribe(args));

await makeServer({
context,
execute: executeFn,
subscribe: subscribeFn,
});

const client = new WebSocket(url, GRAPHQL_TRANSPORT_WS_PROTOCOL);
await new Promise((resolve) => {
client.onopen = () => {
client.send(
stringifyMessage<MessageType.ConnectionInit>({
type: MessageType.ConnectionInit,
}),
);
};
client.onmessage = ({ data }) => {
const message = parseMessage(data);
if (message.type === MessageType.ConnectionAck) {
resolve();
}
};
});

await new Promise((resolve) => {
client.send(
stringifyMessage<MessageType.Subscribe>({
id: '1',
type: MessageType.Subscribe,
payload: {
query: `{ getValue }`,
},
}),
);
client.onmessage = ({ data }) => {
const message = parseMessage(data);
if (message.type === MessageType.Next && message.id === '1') {
resolve();
}
};
});

expect(executeFn).toBeCalled();
expect(executeFn.mock.calls[0][0].contextValue).toBe(context);

await new Promise((resolve) => {
client.send(
stringifyMessage<MessageType.Subscribe>({
id: '2',
type: MessageType.Subscribe,
payload: {
query: `subscription { greetings }`,
},
}),
);
client.onmessage = ({ data }) => {
const message = parseMessage(data);
if (message.type === MessageType.Complete && message.id === '2') {
resolve();
}
};
});

expect(subscribeFn).toBeCalled();
expect(subscribeFn.mock.calls[0][0].contextValue).toBe(context);
});

0 comments on commit 5b3d253

Please sign in to comment.