From cb9dd8ba94cf48afe6b33ecb80c27abbf62363cc Mon Sep 17 00:00:00 2001 From: enisdenjo Date: Wed, 5 Jul 2023 20:06:59 +0200 Subject: [PATCH 1/3] unexport makeResponse and getAcceptableMediaType --- src/handler.ts | 86 ++++++++++++++++++++------------------------------ 1 file changed, 34 insertions(+), 52 deletions(-) diff --git a/src/handler.ts b/src/handler.ts index 8bdf1b19..479b2f71 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -437,7 +437,37 @@ export function createHandler< ]; } - const acceptedMediaType = getAcceptableMediaType(getHeader(req, 'accept')); + let acceptedMediaType: AcceptableMediaType | null = null; + const accepts = (getHeader(req, 'accept') || '*/*') + .replace(/\s/g, '') + .toLowerCase() + .split(','); + for (const accept of accepts) { + // accept-charset became obsolete, shouldnt be used (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset) + // TODO: handle the weight parameter "q" + const [mediaType, ...params] = accept.split(';'); + const charset = + params?.find((param) => param.includes('charset=')) || 'charset=utf8'; // utf-8 is assumed when not specified; + + if ( + mediaType === 'application/graphql-response+json' && + charset === 'charset=utf8' + ) { + acceptedMediaType = 'application/graphql-response+json'; + break; + } + + // application/json should be the default until watershed + if ( + (mediaType === 'application/json' || + mediaType === 'application/*' || + mediaType === '*/*') && + charset === 'charset=utf8' + ) { + acceptedMediaType = 'application/json'; + break; + } + } if (!acceptedMediaType) { return [ null, @@ -670,57 +700,11 @@ export function createHandler< }; } -/** - * Request's Media-Type that the server accepts. - * - * @category Server - */ -export type AcceptableMediaType = +/** Request's Media-Type that the server accepted. */ +type AcceptableMediaType = | 'application/graphql-response+json' | 'application/json'; -/** - * Inspects the request and detects the appropriate/acceptable Media-Type - * looking at the `Accept` header while complying with the GraphQL over HTTP spec. - * - * @category Server - */ -export function getAcceptableMediaType( - acceptHeader: string | null | undefined, -): AcceptableMediaType | null { - let acceptedMediaType: AcceptableMediaType | null = null; - const accepts = (acceptHeader || '*/*') - .replace(/\s/g, '') - .toLowerCase() - .split(','); - for (const accept of accepts) { - // accept-charset became obsolete, shouldnt be used (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset) - // TODO: handle the weight parameter "q" - const [mediaType, ...params] = accept.split(';'); - const charset = - params?.find((param) => param.includes('charset=')) || 'charset=utf8'; // utf-8 is assumed when not specified; - - if ( - mediaType === 'application/graphql-response+json' && - charset === 'charset=utf8' - ) { - acceptedMediaType = 'application/graphql-response+json'; - break; - } - - if ( - (mediaType === 'application/json' || - mediaType === 'application/*' || - mediaType === '*/*') && - charset === 'charset=utf8' - ) { - acceptedMediaType = 'application/json'; - break; - } - } - return acceptedMediaType; -} - /** * Creates an appropriate GraphQL over HTTP response following the provided arguments. * @@ -731,10 +715,8 @@ export function getAcceptableMediaType( * * If the first argument is an `Error`, the operation will be treated as a bad request responding with `400: Bad Request` and the * error will be present in the `ExecutionResult` style. - * - * @category Server */ -export function makeResponse( +function makeResponse( resultOrErrors: | Readonly | Readonly From b87a4ef1413429aa4a35ca0e19094b80d294429f Mon Sep 17 00:00:00 2001 From: enisdenjo Date: Wed, 5 Jul 2023 20:07:19 +0200 Subject: [PATCH 2/3] gendocs --- docs/modules/handler.md | 58 ----------------------------------------- 1 file changed, 58 deletions(-) diff --git a/docs/modules/handler.md b/docs/modules/handler.md index 7a1fcbe5..d166a7a4 100644 --- a/docs/modules/handler.md +++ b/docs/modules/handler.md @@ -12,7 +12,6 @@ ### Type Aliases -- [AcceptableMediaType](handler.md#acceptablemediatype) - [FormatError](handler.md#formaterror) - [Handler](handler.md#handler) - [OperationArgs](handler.md#operationargs) @@ -25,20 +24,10 @@ ### Functions - [createHandler](handler.md#createhandler) -- [getAcceptableMediaType](handler.md#getacceptablemediatype) - [isResponse](handler.md#isresponse) -- [makeResponse](handler.md#makeresponse) ## Server -### AcceptableMediaType - -Ƭ **AcceptableMediaType**: ``"application/graphql-response+json"`` \| ``"application/json"`` - -Request's Media-Type that the server accepts. - -___ - ### FormatError Ƭ **FormatError**: (`err`: `Readonly`<`GraphQLError` \| `Error`\>) => `GraphQLError` \| `Error` @@ -230,25 +219,6 @@ console.log('Listening to port 4000'); ___ -### getAcceptableMediaType - -▸ **getAcceptableMediaType**(`acceptHeader`): [`AcceptableMediaType`](handler.md#acceptablemediatype) \| ``null`` - -Inspects the request and detects the appropriate/acceptable Media-Type -looking at the `Accept` header while complying with the GraphQL over HTTP spec. - -#### Parameters - -| Name | Type | -| :------ | :------ | -| `acceptHeader` | `undefined` \| ``null`` \| `string` | - -#### Returns - -[`AcceptableMediaType`](handler.md#acceptablemediatype) \| ``null`` - -___ - ### isResponse ▸ **isResponse**(`val`): val is Response @@ -264,31 +234,3 @@ Checks whether the passed value is the `graphql-http` server agnostic response. #### Returns val is Response - -___ - -### makeResponse - -▸ **makeResponse**(`resultOrErrors`, `acceptedMediaType`, `formatError`): [`Response`](handler.md#response) - -Creates an appropriate GraphQL over HTTP response following the provided arguments. - -If the first argument is an `ExecutionResult`, the operation will be treated as "successful". - -If the first argument is (an array of) `GraphQLError`, or an `ExecutionResult` without the `data` field, it will be treated -the response will be constructed with the help of `acceptedMediaType` complying with the GraphQL over HTTP spec. - -If the first argument is an `Error`, the operation will be treated as a bad request responding with `400: Bad Request` and the -error will be present in the `ExecutionResult` style. - -#### Parameters - -| Name | Type | -| :------ | :------ | -| `resultOrErrors` | readonly `GraphQLError`[] \| `Readonly`<`ExecutionResult`<`ObjMap`<`unknown`\>, `ObjMap`<`unknown`\>\>\> \| `Readonly`<`GraphQLError`\> \| `Readonly`<`Error`\> | -| `acceptedMediaType` | [`AcceptableMediaType`](handler.md#acceptablemediatype) | -| `formatError` | [`FormatError`](handler.md#formaterror) | - -#### Returns - -[`Response`](handler.md#response) From cc2594881e95da48860ce2934d2cd61a39527788 Mon Sep 17 00:00:00 2001 From: enisdenjo Date: Thu, 6 Jul 2023 17:33:05 +0300 Subject: [PATCH 3/3] unexport isResponse too --- docs/modules/handler.md | 19 ------------------- src/handler.ts | 8 ++------ 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/docs/modules/handler.md b/docs/modules/handler.md index d166a7a4..7903d7a1 100644 --- a/docs/modules/handler.md +++ b/docs/modules/handler.md @@ -24,7 +24,6 @@ ### Functions - [createHandler](handler.md#createhandler) -- [isResponse](handler.md#isresponse) ## Server @@ -216,21 +215,3 @@ console.log('Listening to port 4000'); #### Returns [`Handler`](handler.md#handler)<`RequestRaw`, `RequestContext`\> - -___ - -### isResponse - -▸ **isResponse**(`val`): val is Response - -Checks whether the passed value is the `graphql-http` server agnostic response. - -#### Parameters - -| Name | Type | -| :------ | :------ | -| `val` | `unknown` | - -#### Returns - -val is Response diff --git a/src/handler.ts b/src/handler.ts index 479b2f71..7f75404a 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -123,12 +123,8 @@ export interface ResponseInit { */ export type Response = readonly [body: ResponseBody | null, init: ResponseInit]; -/** - * Checks whether the passed value is the `graphql-http` server agnostic response. - * - * @category Server - */ -export function isResponse(val: unknown): val is Response { +/** Checks whether the passed value is the `graphql-http` server agnostic response. */ +function isResponse(val: unknown): val is Response { // TODO: make sure the contents of init match ResponseInit return ( Array.isArray(val) &&