diff --git a/packages/executors/http/src/createFormDataFromVariables.ts b/packages/executors/http/src/createFormDataFromVariables.ts index aa1a8c13..1b2d07c1 100644 --- a/packages/executors/http/src/createFormDataFromVariables.ts +++ b/packages/executors/http/src/createFormDataFromVariables.ts @@ -9,8 +9,8 @@ import { FormData as DefaultFormData, } from '@whatwg-node/fetch'; import { extractFiles, isExtractableFile } from 'extract-files'; -import { SerializedRequest } from './index.js'; import { isGraphQLUpload } from './isGraphQLUpload.js'; +import { jsonStringifyBody, SerializedRequest } from './utils.js'; function collectAsyncIterableValues( asyncIterable: AsyncIterable, @@ -42,11 +42,10 @@ export function createFormDataFromVariables( }, ) { if (!body.variables) { - return JSON.stringify(body); + return jsonStringifyBody(body); } - const vars = Object.assign({}, body.variables); const { clone, files } = extractFiles( - vars, + body.variables, 'variables', ((v: any) => isExtractableFile(v) || @@ -56,7 +55,7 @@ export function createFormDataFromVariables( typeof v?.arrayBuffer === 'function') as any, ); if (files.size === 0) { - return JSON.stringify(body); + return jsonStringifyBody(body); } const map: Record = {}; const uploads: any[] = []; @@ -69,7 +68,7 @@ export function createFormDataFromVariables( const form = new FormDataCtor(); form.append( 'operations', - JSON.stringify({ + jsonStringifyBody({ ...body, variables: clone, }), diff --git a/packages/executors/http/src/index.ts b/packages/executors/http/src/index.ts index a2ee5bec..e3037b33 100644 --- a/packages/executors/http/src/index.ts +++ b/packages/executors/http/src/index.ts @@ -25,6 +25,7 @@ import { createGraphQLErrorForAbort, createResultForAbort, hashSHA256, + SerializedRequest, } from './utils.js'; export type SyncFetchFn = ( @@ -122,13 +123,6 @@ export interface HTTPExecutorOptions { disposable?: boolean; } -export type SerializedRequest = { - query?: string; - variables?: Record; - operationName?: string; - extensions?: any; -}; - export type HeadersConfig = Record; // To prevent event listener warnings @@ -257,7 +251,7 @@ export function buildHTTPExecutor( ? request.operationName : undefined, extensions: - request.extensions && Object.keys(request.extensions).length > 0 + (request.extensions && Object.keys(request.extensions).length > 0) ? request.extensions : undefined, }; diff --git a/packages/executors/http/src/prepareGETUrl.ts b/packages/executors/http/src/prepareGETUrl.ts index 5559a970..8e71191d 100644 --- a/packages/executors/http/src/prepareGETUrl.ts +++ b/packages/executors/http/src/prepareGETUrl.ts @@ -1,4 +1,4 @@ -import { SerializedRequest } from '.'; +import { SerializedRequest } from './utils.js'; export function prepareGETUrl({ baseUrl = '', diff --git a/packages/executors/http/src/utils.ts b/packages/executors/http/src/utils.ts index ea300303..d9c78dea 100644 --- a/packages/executors/http/src/utils.ts +++ b/packages/executors/http/src/utils.ts @@ -37,3 +37,42 @@ export function hashSHA256(str: string) { }, ); } + +export type SerializedRequest = { + query?: string; + variables?: Record; + operationName?: string; + extensions?: any; +}; + +// For faster serialization instead of JSON.stringify overhead +export function jsonStringifyBody(body: SerializedRequest) { + let str = '{'; + let prev = false; + if (body.query) { + str += `"query":"${body.query.replaceAll('"', '\\"')}"`; + prev = true; + } + if (body.variables) { + if (prev) { + str += ','; + } + str += `"variables":${JSON.stringify(body.variables)}`; + prev = true; + } + if (body.operationName) { + if (prev) { + str += ','; + } + str += `"operationName":"${body.operationName}"`; + prev = true; + } + if (body.extensions) { + if (prev) { + str += ','; + } + str += `"extensions":${JSON.stringify(body.extensions)}`; + } + str += '}'; + return str; +} \ No newline at end of file