diff --git a/.changeset/graphql-yoga-3237-dependencies.md b/.changeset/graphql-yoga-3237-dependencies.md new file mode 100644 index 0000000000..a1df413065 --- /dev/null +++ b/.changeset/graphql-yoga-3237-dependencies.md @@ -0,0 +1,7 @@ +--- +'graphql-yoga': patch +--- +dependencies updates: + - Updated dependency [`@whatwg-node/server@^0.9.33` + ↗︎](https://www.npmjs.com/package/@whatwg-node/server/v/0.9.33) (from `^0.9.32`, in + `dependencies`) diff --git a/.changeset/smart-melons-beam.md b/.changeset/smart-melons-beam.md new file mode 100644 index 0000000000..6343e33f89 --- /dev/null +++ b/.changeset/smart-melons-beam.md @@ -0,0 +1,6 @@ +--- +'graphql-yoga': patch +--- + +In such environments like CloudFlare Workers, the `request` object in the context always has the initial request object, so it was impossible to access the actual `Request` object from the execution context. +Now Yoga ensures that the `request` in the context is the same with the actual `Request`. \ No newline at end of file diff --git a/packages/graphql-yoga/__tests__/requests.spec.ts b/packages/graphql-yoga/__tests__/requests.spec.ts index a4d7be03f9..a8b1a79920 100644 --- a/packages/graphql-yoga/__tests__/requests.spec.ts +++ b/packages/graphql-yoga/__tests__/requests.spec.ts @@ -1,4 +1,6 @@ -import { createSchema, createYoga } from '../src'; +import { OnExecuteHook } from '@envelop/core'; +import { Request } from '@whatwg-node/fetch'; +import { createSchema, createYoga, YogaInitialContext } from '../src'; describe('requests', () => { const schema = createSchema({ @@ -453,4 +455,60 @@ describe('requests', () => { const body = await response.text(); expect(body).toBeFalsy(); }); + + it('contains the correct request object in the unique execution context', async () => { + const onExecuteFn = jest.fn((() => {}) as OnExecuteHook); + const yoga = createYoga({ + schema: createSchema({ + typeDefs: /* GraphQL */ ` + type Query { + greetings: String + } + `, + resolvers: { + Query: { + greetings: (_, __, ctx) => { + return `Hello world!`; + }, + }, + }, + }), + plugins: [ + { + onExecute: onExecuteFn, + }, + ], + }); + const env = {}; + const extraCtx = {}; + const firstReq = new Request('http://yoga/graphql', { + method: 'POST', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify({ query: '{ greetings }' }), + }); + const firstRes = await yoga.fetch(firstReq, env, extraCtx); + expect(firstRes.status).toBe(200); + const firstResBody = await firstRes.json(); + expect(firstResBody.data.greetings).toBe('Hello world!'); + expect(onExecuteFn).toHaveBeenCalledTimes(1); + expect(onExecuteFn.mock.calls[0][0].args.contextValue.request).toBe(firstReq); + const secondReq = new Request('http://yoga/graphql', { + method: 'POST', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify({ query: '{ greetings }' }), + }); + const secondRes = await yoga.fetch(secondReq, env, extraCtx); + expect(secondRes.status).toBe(200); + const secondResBody = await secondRes.json(); + expect(secondResBody.data.greetings).toBe('Hello world!'); + expect(onExecuteFn).toHaveBeenCalledTimes(2); + expect(onExecuteFn.mock.calls[1][0].args.contextValue.request).toBe(secondReq); + expect(onExecuteFn.mock.calls[1][0].args.contextValue).not.toBe( + onExecuteFn.mock.calls[0][0].args.contextValue, + ); + }); }); diff --git a/packages/graphql-yoga/package.json b/packages/graphql-yoga/package.json index 46ff461e66..af4b2ec860 100644 --- a/packages/graphql-yoga/package.json +++ b/packages/graphql-yoga/package.json @@ -56,7 +56,7 @@ "@graphql-yoga/logger": "^2.0.0", "@graphql-yoga/subscription": "^5.0.0", "@whatwg-node/fetch": "^0.9.17", - "@whatwg-node/server": "^0.9.32", + "@whatwg-node/server": "^0.9.33", "dset": "^3.1.1", "lru-cache": "^10.0.0", "tslib": "^2.5.2" diff --git a/packages/graphql-yoga/src/server.ts b/packages/graphql-yoga/src/server.ts index 3065e6f83d..46d54dc9e0 100644 --- a/packages/graphql-yoga/src/server.ts +++ b/packages/graphql-yoga/src/server.ts @@ -463,14 +463,15 @@ export class YogaServer< } if (result == null) { - const additionalContext = args[0]?.request - ? { - params, - } - : { - request, - params, - }; + const additionalContext = + args[0]?.request === request + ? { + params, + } + : { + request, + params, + }; const initialContext = args[0] ? batched diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index daca3ff25a..c227f26303 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -389,7 +389,7 @@ importers: dependencies: '@whatwg-node/server-plugin-cookies': specifier: ^1.0.0 - version: 1.0.0(@whatwg-node/server@0.9.32) + version: 1.0.0(@whatwg-node/server@0.9.33) graphql: specifier: 16.6.0 version: 16.6.0 @@ -1639,8 +1639,8 @@ importers: specifier: ^0.9.17 version: 0.9.17 '@whatwg-node/server': - specifier: ^0.9.32 - version: 0.9.32 + specifier: ^0.9.33 + version: 0.9.33 dset: specifier: ^3.1.1 version: 3.1.2 @@ -14313,14 +14313,14 @@ packages: fast-querystring: 1.1.1 tslib: 2.6.2 - /@whatwg-node/server-plugin-cookies@1.0.0(@whatwg-node/server@0.9.32): + /@whatwg-node/server-plugin-cookies@1.0.0(@whatwg-node/server@0.9.33): resolution: {integrity: sha512-o0MqK6H4Yhxht+J+cgZIpEhdb4SID1grFWfOiMdni3csNHBKZ+MKAFhxS+6wAJsarHN7BEZ0QMu4PG09Uwhr2g==} engines: {node: '>=16.0.0'} peerDependencies: '@whatwg-node/server': ^0.9.0 dependencies: '@whatwg-node/cookie-store': 0.2.0 - '@whatwg-node/server': 0.9.32 + '@whatwg-node/server': 0.9.33 tslib: 2.5.3 dev: false @@ -14332,8 +14332,8 @@ packages: tslib: 2.6.2 dev: false - /@whatwg-node/server@0.9.32: - resolution: {integrity: sha512-PRTRE8ZhObwYx9yRoUdxYkrhCoDk2vyDA5BtaG+NAqEmU1wwbwlXUpaeRRrPuGaM7ScbIkueU25A0GJIRQzccw==} + /@whatwg-node/server@0.9.33: + resolution: {integrity: sha512-bHWZi6YhVsDKAzjlPn5EN7u5j7SvHqDI6Acr37hgMBjKyCzqHivfPFgC/sRZ6LLxM9pJNsXpFoAF1kySXhAn6w==} engines: {node: '>=16.0.0'} dependencies: '@whatwg-node/fetch': 0.9.17