Skip to content

Commit

Permalink
feat(json-schema/oas/raml): timeout option (#5261)
Browse files Browse the repository at this point in the history
* feat(json-schema/oas/raml): `timeout` option

* Try clear timeouts
  • Loading branch information
ardatan committed Mar 28, 2023
1 parent 51afc94 commit a1e0819
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 3 deletions.
9 changes: 9 additions & 0 deletions .changeset/forty-planets-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@graphql-mesh/json-schema': minor
'@omnigraph/json-schema': minor
'@graphql-mesh/openapi': minor
'@graphql-mesh/raml': minor
'@graphql-mesh/types': patch
---

`timeout` option for HTTP requests
5 changes: 5 additions & 0 deletions packages/handlers/json-schema/yaml-config.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ type JsonSchemaHandler @md {
Will be removed later
"""
bundleHeaders: JSON

"""
Timeout for the HTTP request in milliseconds
"""
timeout: Int
}

enum JsonSchemaOperationType {
Expand Down
5 changes: 5 additions & 0 deletions packages/handlers/openapi/yaml-config.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ type OpenapiHandler @md {
"""
queryParams: JSON

"""
Timeout for the HTTP request in milliseconds
"""
timeout: Int

bundle: Boolean
}

Expand Down
5 changes: 5 additions & 0 deletions packages/handlers/raml/yaml-config.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ type RAMLHandler {
selectQueryOrMutationField: [RAMLSelectQueryOrMutationFieldConfig]
queryParams: Any
bundle: Boolean

"""
Timeout for the HTTP request in milliseconds
"""
timeout: Int
}

enum QueryOrMutation {
Expand Down
7 changes: 6 additions & 1 deletion packages/loaders/json-schema/src/addRootFieldResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { stringInterpolator } from '@graphql-mesh/string-interpolation';
import { Logger, MeshFetch } from '@graphql-mesh/types';
import { getHeadersObj } from '@graphql-mesh/utils';
import { createGraphQLError, memoize1 } from '@graphql-tools/utils';
import { Blob, File, FormData } from '@whatwg-node/fetch';
import { AbortSignal, Blob, File, FormData } from '@whatwg-node/fetch';
import { resolveDataByUnionInputType } from './resolveDataByUnionInputType.js';
import { HTTPMethod } from './types.js';
import { isFileUpload } from './utils.js';
Expand Down Expand Up @@ -50,6 +50,7 @@ export interface HTTPRootFieldResolverOpts {
export interface GlobalOptions {
sourceName: string;
endpoint: string;
timeout: number;
operationHeaders: Record<string, string>;
queryStringOptions: IStringifyOptions;
queryParams: Record<string, string | number | boolean>;
Expand All @@ -72,6 +73,7 @@ export function addHTTPRootFieldResolver(
{
sourceName,
endpoint,
timeout,
operationHeaders: globalOperationHeaders,
queryStringOptions: globalQueryStringOptions = {},
queryParams: globalQueryParams,
Expand Down Expand Up @@ -110,6 +112,9 @@ export function addHTTPRootFieldResolver(
method: httpMethod,
headers,
};
if (timeout) {
requestInit.signal = AbortSignal.timeout(timeout);
}
// Handle binary data
if (isBinary) {
const binaryUpload = await args.input;
Expand Down
1 change: 1 addition & 0 deletions packages/loaders/json-schema/src/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ interface ProcessDirectiveArgs {
logger: Logger;
globalFetch: MeshFetch;
endpoint?: string;
timeout?: number;
operationHeaders?: Record<string, string>;
queryParams?: Record<string, any>;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DefaultLogger } from '@graphql-mesh/utils';
import { fetch } from '@whatwg-node/fetch';
import { createBundleFromDereferencedSchema } from './bundle.js';
import { processDirectives } from './directives.js';
import { getDereferencedJSONSchemaFromOperations } from './getDereferencedJSONSchemaFromOperations.js';
Expand Down Expand Up @@ -56,7 +57,7 @@ export async function loadGraphQLSchemaFromJSONSchemas(
...options,
operationHeaders: typeof options.operationHeaders === 'object' ? options.operationHeaders : {},
schema: graphqlSchema,
globalFetch: options.fetch,
globalFetch: options.fetch || fetch,
pubsub: options.pubsub,
logger: options.logger,
});
Expand Down
1 change: 1 addition & 0 deletions packages/loaders/json-schema/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { BaseLoaderOptions } from '@graphql-tools/utils';
export interface JSONSchemaLoaderOptions extends BaseLoaderOptions {
endpoint?: string;
operationHeaders?: OperationHeadersConfiguration;
timeout?: number;
schemaHeaders?: Record<string, string>;
operations: JSONSchemaOperationConfig[];
errorMessage?: string;
Expand Down
51 changes: 51 additions & 0 deletions packages/loaders/json-schema/test/timeout.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* eslint-disable import/no-nodejs-modules */
import { createServer, Server } from 'http';
import { AddressInfo } from 'net';
import { execute, OperationTypeNode, parse } from 'graphql';
import { fetch } from '@whatwg-node/fetch';
import { loadGraphQLSchemaFromJSONSchemas } from '../src/loadGraphQLSchemaFromJSONSchemas';

describe('Timeout', () => {
let server: Server;
let timeout: NodeJS.Timeout;
beforeAll(async () => {
server = createServer((req, res) => {
timeout = setTimeout(() => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('test');
}, 500);
});
await new Promise<void>(resolve => server.listen(0, resolve));
});
afterAll(async () => {
clearTimeout(timeout);
await new Promise(resolve => server.close(resolve));
});
it('should timeout correctly', async () => {
const schema = await loadGraphQLSchemaFromJSONSchemas('test', {
fetch,
timeout: 300,
endpoint: `http://localhost:${(server.address() as AddressInfo).port}`,
operations: [
{
type: OperationTypeNode.QUERY,
field: 'test',
method: 'GET',
path: '/test',
responseSchema: {
type: 'object',
},
},
],
});
const result = await execute({
schema,
document: parse(/* GraphQL */ `
query {
test
}
`),
});
expect(result?.errors?.[0]?.message).toContain('timeout in 300 ms');
});
});
12 changes: 12 additions & 0 deletions packages/types/src/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,10 @@
"type": "object",
"properties": {},
"description": "Will be removed later"
},
"timeout": {
"type": "integer",
"description": "Timeout for the HTTP request in milliseconds"
}
}
},
Expand Down Expand Up @@ -1880,6 +1884,10 @@
"properties": {},
"description": "JSON object representing the query search parameters to add to the API calls"
},
"timeout": {
"type": "integer",
"description": "Timeout for the HTTP request in milliseconds"
},
"bundle": {
"type": "boolean"
}
Expand Down Expand Up @@ -2905,6 +2913,10 @@
},
"bundle": {
"type": "boolean"
},
"timeout": {
"type": "integer",
"description": "Timeout for the HTTP request in milliseconds"
}
},
"required": ["source"]
Expand Down
12 changes: 12 additions & 0 deletions packages/types/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,10 @@ export interface JsonSchemaHandler {
bundleHeaders?: {
[k: string]: any;
};
/**
* Timeout for the HTTP request in milliseconds
*/
timeout?: number;
}
export interface JsonSchemaHTTPOperation {
/**
Expand Down Expand Up @@ -847,6 +851,10 @@ export interface OpenapiHandler {
queryParams?: {
[k: string]: any;
};
/**
* Timeout for the HTTP request in milliseconds
*/
timeout?: number;
bundle?: boolean;
}
export interface OASSelectQueryOrMutationFieldConfig {
Expand Down Expand Up @@ -910,6 +918,10 @@ export interface RAMLHandler {
selectQueryOrMutationField?: RAMLSelectQueryOrMutationFieldConfig[];
queryParams?: any;
bundle?: boolean;
/**
* Timeout for the HTTP request in milliseconds
*/
timeout?: number;
}
export interface RAMLSelectQueryOrMutationFieldConfig {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,5 @@ Note: when using arrayFormat set to 'comma', you can also pass the commaRoundTri
* `commaRoundTrip` (type: `Boolean`) - Even if there is a single item in an array, this option treats them as arrays
(default: false)
* `bundlePath` (type: `String`) - Will be removed later
* `bundleHeaders` (type: `JSON`) - Will be removed later
* `bundleHeaders` (type: `JSON`) - Will be removed later
* `timeout` (type: `Int`) - Timeout for the HTTP request in milliseconds
1 change: 1 addition & 0 deletions website/src/generated-markdown/OpenapiHandler.generated.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ Default: false
* `type` (type: `String (query | mutation | Query | Mutation)`, required)
* `fieldName` (type: `String`, required)
* `queryParams` (type: `JSON`) - JSON object representing the query search parameters to add to the API calls
* `timeout` (type: `Int`) - Timeout for the HTTP request in milliseconds
* `bundle` (type: `Boolean`)

0 comments on commit a1e0819

Please sign in to comment.