Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(json-schema/oas/raml): timeout option #5261

Merged
merged 2 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`)