diff --git a/.changeset/early-donkeys-join.md b/.changeset/early-donkeys-join.md new file mode 100644 index 00000000000..2cd079b9108 --- /dev/null +++ b/.changeset/early-donkeys-join.md @@ -0,0 +1,5 @@ +--- +'@graphql-tools/executor-graphql-ws': minor +--- + +Read and use `connectionParams` from operation extensions diff --git a/packages/executors/graphql-ws/src/index.ts b/packages/executors/graphql-ws/src/index.ts index 1d7c95e12e1..acf16622ee9 100644 --- a/packages/executors/graphql-ws/src/index.ts +++ b/packages/executors/graphql-ws/src/index.ts @@ -13,12 +13,20 @@ function isClient(client: Client | GraphQLWSExecutorOptions): client is Client { export function buildGraphQLWSExecutor(clientOptionsOrClient: GraphQLWSExecutorOptions | Client): Executor { let graphqlWSClient: Client; + let executorConnectionParams = {}; if (isClient(clientOptionsOrClient)) { graphqlWSClient = clientOptionsOrClient; } else { graphqlWSClient = createClient({ webSocketImpl: WebSocket, lazy: true, + connectionParams: () => { + const optionsConnectionParams = + (typeof clientOptionsOrClient.connectionParams === 'function' + ? clientOptionsOrClient.connectionParams() + : clientOptionsOrClient.connectionParams) || {}; + return Object.assign(optionsConnectionParams, executorConnectionParams); + }, ...clientOptionsOrClient, }); if (clientOptionsOrClient.onClient) { @@ -40,6 +48,11 @@ export function buildGraphQLWSExecutor(clientOptionsOrClient: GraphQLWSExecutorO extensions, operationType = getOperationASTFromRequest(executionRequest).operation, } = executionRequest; + // additional connection params can be supplied through the "connectionParams" field in extensions. + // TODO: connection params only from the FIRST operation in lazy mode will be used (detect connectionParams changes and reconnect, too implicit?) + if (extensions?.['connectionParams'] && typeof extensions?.['connectionParams'] === 'object') { + executorConnectionParams = Object.assign(executorConnectionParams, extensions['connectionParams']); + } const query = print(document); const iterableIterator = graphqlWSClient.iterate({ query, diff --git a/packages/executors/legacy-ws/src/index.ts b/packages/executors/legacy-ws/src/index.ts index 7f9840d096c..88e8a68ab2c 100644 --- a/packages/executors/legacy-ws/src/index.ts +++ b/packages/executors/legacy-ws/src/index.ts @@ -16,7 +16,7 @@ export enum LEGACY_WS { } export interface LegacyWSExecutorOpts { - connectionParams?: Record; + connectionParams?: Record | (() => Record); headers?: Record; } @@ -25,6 +25,7 @@ export function buildWSLegacyExecutor( WebSocketImpl: typeof WebSocket, options?: LegacyWSExecutorOpts ): Executor { + let executorConnectionParams = {}; let websocket: WebSocket | null = null; const ensureWebsocket = (errorHandler: (error: Error) => void = err => console.error(err)) => { @@ -46,6 +47,7 @@ export function buildWSLegacyExecutor( payload = options?.connectionParams; break; } + payload = Object.assign(payload, executorConnectionParams); websocket!.send( JSON.stringify({ type: LEGACY_WS.CONNECTION_INIT, @@ -82,6 +84,12 @@ export function buildWSLegacyExecutor( }; return function legacyExecutor(request: ExecutionRequest) { + // additional connection params can be supplied through the "connectionParams" field in extensions. + // TODO: connection params only from the FIRST operation in lazy mode will be used (detect connectionParams changes and reconnect, too implicit?) + if (request.extensions?.['connectionParams'] && typeof request.extensions?.['connectionParams'] === 'object') { + executorConnectionParams = Object.assign(executorConnectionParams, request.extensions['connectionParams']); + } + const id = Date.now().toString(); return observableToAsyncIterable({ subscribe(observer) { diff --git a/packages/loaders/url/src/index.ts b/packages/loaders/url/src/index.ts index 32317e4df6f..a6225d900fe 100644 --- a/packages/loaders/url/src/index.ts +++ b/packages/loaders/url/src/index.ts @@ -91,7 +91,7 @@ export interface LoadFromUrlOptions extends BaseLoaderOptions, Partial | (() => Record); /** * Enable Batching */ @@ -154,7 +154,7 @@ export class UrlLoader implements Loader { buildWSExecutor( subscriptionsEndpoint: string, webSocketImpl: typeof WebSocket, - connectionParams?: Record + connectionParams?: Record | (() => Record) ): Executor { const WS_URL = switchProtocols(subscriptionsEndpoint, { https: 'wss',