From 8b04f1ff37ea824c6a6179776c20183dfebae341 Mon Sep 17 00:00:00 2001 From: Frane Bandov Date: Wed, 30 Oct 2019 12:05:52 +0100 Subject: [PATCH] GraphQL support --- .../nodes-base/nodes/GraphQL/GraphQL.node.ts | 228 ++++++++++++++++++ packages/nodes-base/package.json | 1 + 2 files changed, 229 insertions(+) create mode 100644 packages/nodes-base/nodes/GraphQL/GraphQL.node.ts diff --git a/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts b/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts new file mode 100644 index 0000000000..8c5e438af1 --- /dev/null +++ b/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts @@ -0,0 +1,228 @@ +import { IExecuteFunctions } from 'n8n-core'; +import { + INodeExecutionData, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; + +import { OptionsWithUri } from 'request'; +import { RequestPromiseOptions } from 'request-promise-native'; + +export class GraphQL implements INodeType { + description: INodeTypeDescription = { + displayName: 'GraphQL', + name: 'graphql', + group: ['input'], + version: 1, + description: 'Makes a GraphQL request and returns the received data', + defaults: { + name: 'GraphQL', + color: '#E10098', + }, + inputs: ['main'], + outputs: ['main'], + properties: [ + { + displayName: 'HTTP Request Method', + name: 'requestMethod', + type: 'options', + options: [ + { + name: 'GET', + value: 'GET' + }, + { + name: 'POST', + value: 'POST' + }, + ], + default: 'POST', + description: 'The underlying HTTP request method to use.', + }, + { + displayName: 'Endpoint', + name: 'endpoint', + type: 'string', + default: '', + placeholder: 'http://example.com/graphql', + description: 'The GraphQL endpoint.', + required: true, + }, + { + displayName: 'Ignore SSL Issues', + name: 'allowUnauthorizedCerts', + type: 'boolean', + default: false, + description: 'Still fetch the response even if SSL certificate validation is not possible.', + }, + { + displayName: 'Request Format', + name: 'requestFormat', + type: 'options', + required: true, + options: [ + { + name: 'GraphQL (raw)', + value: 'graphql' + }, + { + name: 'JSON', + value: 'json' + }, + ], + displayOptions: { + show: { + requestMethod: [ + "POST" + ], + }, + }, + default: 'graphql', + description: 'The format for the query payload', + }, + { + displayName: 'Query', + name: 'query', + type: 'json', + default: '', + description: 'GraphQL query', + required: true, + }, + { + displayName: 'Variables', + name: 'variables', + type: 'json', + default: {}, + description: 'Query variables', + displayOptions: { + show: { + requestFormat: [ + "json" + ], + requestMethod: [ + "POST" + ], + }, + }, + }, + { + displayName: 'Operation Name', + name: 'operationName', + type: 'string', + default: '', + description: 'Name of operation to execute', + displayOptions: { + show: { + requestFormat: [ + "json" + ], + requestMethod: [ + "POST" + ], + }, + }, + }, + { + displayName: 'Response Format', + name: 'responseFormat', + type: 'options', + options: [ + { + name: 'JSON', + value: 'json' + }, + { + name: 'String', + value: 'string' + }, + ], + default: 'json', + description: 'The format in which the data gets returned from the URL.', + }, + { + displayName: 'Response Data Property Name', + name: 'dataPropertyName', + type: 'string', + default: 'response', + required: true, + displayOptions: { + show: { + responseFormat: [ + 'string', + ], + }, + }, + description: 'Name of the property to which to write the response data.', + }, + ] + }; + + + async execute(this: IExecuteFunctions): Promise { + + const items = this.getInputData(); + + let requestOptions: OptionsWithUri & RequestPromiseOptions; + + const returnItems: INodeExecutionData[] = []; + for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { + const requestMethod = this.getNodeParameter('requestMethod', itemIndex, 'POST') as string; + const endpoint = this.getNodeParameter('endpoint', itemIndex, '') as string; + const requestFormat = this.getNodeParameter('requestFormat', itemIndex, 'graphql') as string; + const responseFormat = this.getNodeParameter('responseFormat', 0) as string; + + requestOptions = { + headers: { + 'content-type': `application/${requestFormat}`, + }, + method: requestMethod, + uri: endpoint, + simple: false, + rejectUnauthorized: !this.getNodeParameter('allowUnauthorizedCerts', itemIndex, false) as boolean, + }; + + const gqlQuery = this.getNodeParameter('query', itemIndex, '') as string; + if (requestMethod === 'GET') { + requestOptions.qs = { + query: gqlQuery + }; + } else { + if (requestFormat === 'json') { + requestOptions.body = { + query: gqlQuery, + variables: this.getNodeParameter('variables', itemIndex, {}) as object, + operationName: this.getNodeParameter('operationName', itemIndex, null) as string, + }; + if (typeof requestOptions.body.variables === "string") { + requestOptions.body.variables = {}; + } + if (requestOptions.body.operationName === "") { + requestOptions.body.operation = null; + } + requestOptions.json = true; + } else { + requestOptions.body = gqlQuery; + } + } + + const response = await this.helpers.request(requestOptions); + if (responseFormat === 'string') { + const dataPropertyName = this.getNodeParameter('dataPropertyName', 0) as string; + + returnItems.push({ + json: { + [dataPropertyName]: response, + } + }); + } else { + if (typeof response === 'string') { + throw new Error('Response body is not valid JSON. Change "Response Format" to "String"'); + } + + returnItems.push({ json: response }); + } + } + + return this.prepareOutputData(returnItems); + } +} diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 559b53dade..b216508861 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -80,6 +80,7 @@ "dist/nodes/Gitlab/GitlabTrigger.node.js", "dist/nodes/Google/GoogleDrive.node.js", "dist/nodes/Google/GoogleSheets.node.js", + "dist/nodes/GraphQL/GraphQL.node.js", "dist/nodes/HttpRequest.node.js", "dist/nodes/If.node.js", "dist/nodes/Interval.node.js",