From dd91a2c3ae5b141a7475f98f290997ed4b0dbd9a Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Wed, 29 Apr 2020 21:57:36 -0400 Subject: [PATCH] Add Facebook Graph API node --- .../credentials/GraphApi.credentials.ts | 18 + .../nodes/Facebook/GraphApi.node.ts | 416 ++++++++++++++++++ .../nodes-base/nodes/Facebook/facebook.png | Bin 0 -> 24576 bytes packages/nodes-base/package.json | 2 + 4 files changed, 436 insertions(+) create mode 100644 packages/nodes-base/credentials/GraphApi.credentials.ts create mode 100644 packages/nodes-base/nodes/Facebook/GraphApi.node.ts create mode 100644 packages/nodes-base/nodes/Facebook/facebook.png diff --git a/packages/nodes-base/credentials/GraphApi.credentials.ts b/packages/nodes-base/credentials/GraphApi.credentials.ts new file mode 100644 index 0000000000..132ba38e77 --- /dev/null +++ b/packages/nodes-base/credentials/GraphApi.credentials.ts @@ -0,0 +1,18 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + + +export class GraphApi implements ICredentialType { + name = 'graphApi'; + displayName = 'Graph API'; + properties = [ + { + displayName: 'Access Token', + name: 'accessToken', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Facebook/GraphApi.node.ts b/packages/nodes-base/nodes/Facebook/GraphApi.node.ts new file mode 100644 index 0000000000..a81894c138 --- /dev/null +++ b/packages/nodes-base/nodes/Facebook/GraphApi.node.ts @@ -0,0 +1,416 @@ +import { + BINARY_ENCODING, + IExecuteFunctions, +} from 'n8n-core'; +import { + IBinaryData, + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; + +import { OptionsWithUri } from 'request'; + +export class GraphApi implements INodeType { + description: INodeTypeDescription = { + displayName: 'Graph API', + name: 'graphApi', + icon: 'file:facebook.png', + group: ['transform'], + version: 1, + description: 'Interacts with Facebook using the Graph API', + defaults: { + name: 'Graph API', + color: '#772244', + }, + inputs: ['main'], + outputs: ['main', 'main'], + outputNames: ['success', 'failure'], + credentials: [ + { + name: 'graphApi', + required: true, + }, + ], + properties: [ + { + displayName: 'Host URL', + name: 'hostUrl', + type: 'options', + options: [ + { + name: 'Default', + value: 'graph.facebook.com', + }, + { + name: 'Video Uploads', + value: 'graph-video.facebook.com', + } + ], + default: 'graph.facebook.com', + description: 'The Host URL of the request. Almost all requests are passed to the graph.facebook.com host URL. The single exception is video uploads, which use graph-video.facebook.com.', + required: true, + }, + { + displayName: 'HTTP Request Method', + name: 'httpRequestMethod', + type: 'options', + options: [ + { + name: 'GET', + value: 'GET', + }, + { + name: 'POST', + value: 'POST', + }, + { + name: 'DELETE', + value: 'DELETE', + }, + ], + default: 'GET', + description: 'The HTTP Method to be used for the request.', + required: true, + }, + { + displayName: 'Graph API Version', + name: 'graphApiVersion', + type: 'options', + options: [ + { + name: 'Latest', + value: '', + }, + { + name: 'v6.0', + value: 'v6.0/', + }, + { + name: 'v5.0', + value: 'v5.0/', + }, + { + name: 'v4.0', + value: 'v4.0/', + }, + { + name: 'v3.3', + value: 'v3.3/', + }, + { + name: 'v3.2', + value: 'v3.2/', + }, + { + name: 'v3.1', + value: 'v3.1/', + }, + { + name: 'v3.0', + value: 'v3.0/', + }, + { + name: 'v2.12', + value: 'v2.12/', + }, + ], + default: '', + description: 'The version of the Graph API to be used in the request.', + required: true, + }, + { + displayName: 'Node', + name: 'node', + type: 'string', + default: '', + description: 'The node on which to operate. A node is an individual object with a unique ID. For example, there are many User node objects, each with a unique ID representing a person on Facebook.', + placeholder: 'me', + required: true, + }, + { + displayName: 'Edge', + name: 'edge', + type: 'string', + default: '', + description: 'Edge of the node on which to operate. Edges represent collections of objects wich are attached to the node.', + placeholder: 'videos', + required: false, + }, + { + displayName: 'Send Binary Data', + name: 'sendBinaryData', + type: 'boolean', + displayOptions: { + show: { + httpRequestMethod: [ + 'POST', + 'PUT', + ], + }, + }, + default: false, + required: true, + description: 'If binary data should be send as body.', + }, + { + displayName: 'Binary Property', + name: 'binaryPropertyName', + type: 'string', + required: false, + default: '', + placeholder: 'file:data', + displayOptions: { + hide: { + sendBinaryData: [ + false, + ], + }, + show: { + httpRequestMethod: [ + 'POST', + 'PUT', + ], + }, + }, + description: `Name of the binary property which contains the data for the file to be uploaded.
+ For Form-Data Multipart, multiple can be provided in the format:
+ "sendKey1:binaryProperty1,sendKey2:binaryProperty2`, + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: 'Fields', + name: 'fields', + placeholder: 'Add Field', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + displayOptions: { + show: { + '/httpRequestMethod': [ + 'GET', + ], + }, + }, + description: 'The list of fields to request in the GET request.', + default: {}, + options: [ + { + name: 'field', + displayName: 'Field', + values: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the field.', + }, + ], + }, + ], + }, + { + displayName: 'Query Parameters', + name: 'queryParameters', + placeholder: 'Add Parameter', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + description: 'The query parameters to send', + default: {}, + options: [ + { + name: 'parameter', + displayName: 'Parameter', + values: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the parameter.', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + description: 'Value of the parameter.', + }, + ], + }, + ], + }, + { + displayName: 'Query Parameters JSON', + name: 'queryParametersJson', + type: 'json', + default: '{}', + placeholder: '{\"field_name\": \"field_value\"}', + description: 'The query parameters to send, defined as a JSON object', + required: false, + } + ], + }, + ], + }; + + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + + let response: any; // tslint:disable-line:no-any + const successItems: INodeExecutionData[] = []; + const failureItems: INodeExecutionData[] = []; + + for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { + const graphApiCredentials = this.getCredentials('graphApi'); + + const hostUrl = this.getNodeParameter('hostUrl', itemIndex) as string; + const httpRequestMethod = this.getNodeParameter('httpRequestMethod', itemIndex) as string; + const graphApiVersion = this.getNodeParameter('graphApiVersion', itemIndex) as string; + const node = this.getNodeParameter('node', itemIndex) as string; + const edge = this.getNodeParameter('edge', itemIndex) as string; + const options = this.getNodeParameter('options', itemIndex, {}) as IDataObject; + + let uri = `https://${hostUrl}/${graphApiVersion}${node}`; + if (edge) { + uri = `${uri}/${edge}`; + } + + const requestOptions : OptionsWithUri = { + headers: { + accept: 'application/json,text/*;q=0.99', + }, + method: httpRequestMethod, + uri, + json: true, + gzip: true, + qs: { + access_token: graphApiCredentials!.accessToken, + }, + }; + + if (options !== undefined) { + // Build fields query parameter as a comma separated list + if (options.fields !== undefined) { + const fields = options.fields as IDataObject; + if (fields.field !== undefined) { + const fieldsCsv = (fields.field as IDataObject[]).map(field => field.name).join(','); + requestOptions.qs.fields = fieldsCsv; + } + } + + // Add the query parameters defined in the UI + if (options.queryParameters !== undefined) { + const queryParameters = options.queryParameters as IDataObject; + + if (queryParameters.parameter != undefined) { + for (const queryParameter of queryParameters.parameter as IDataObject[]) { + requestOptions.qs[queryParameter.name as string] = queryParameter.value; + } + } + } + + // Add the query parameters defined as a JSON object + if (options.queryParametersJson) { + let queryParametersJsonObj = {}; + try + { + queryParametersJsonObj = JSON.parse(options.queryParametersJson as string); + } catch { /* Do nothing, at least for now */} + const qs = requestOptions.qs; + requestOptions.qs = { + ...qs, + ...queryParametersJsonObj, + }; + } + } + + const sendBinaryData = this.getNodeParameter('sendBinaryData', itemIndex, false) as boolean; + if (sendBinaryData) { + const item = items[itemIndex]; + if (item.binary === undefined) { + throw new Error('No binary data exists on item!'); + } + + const binaryPropertyNameFull = this.getNodeParameter('binaryPropertyName', itemIndex) as string; + + let propertyName = 'file'; + let binaryPropertyName = binaryPropertyNameFull; + if (binaryPropertyNameFull.includes(':')) { + const binaryPropertyNameParts = binaryPropertyNameFull.split(':'); + propertyName = binaryPropertyNameParts[0]; + binaryPropertyName = binaryPropertyNameParts[1]; + } + + if (item.binary[binaryPropertyName] === undefined) { + throw new Error(`No binary data property "${binaryPropertyName}" does not exists on item!`); + } + + const binaryProperty = item.binary[binaryPropertyName] as IBinaryData; + + requestOptions.formData = { + [propertyName]: { + value: Buffer.from(binaryProperty.data, BINARY_ENCODING), + options: { + filename: binaryProperty.fileName, + contentType: binaryProperty.mimeType, + }, + }, + }; + } + + try { + // Now that the options are all set make the actual http request + response = await this.helpers.request(requestOptions); + } catch (error) { + if (this.continueOnFail() === false) { + throw error; + } + + let errorItem; + if (error.response !== undefined) { + // Since this is a Graph API node and we already know the request was + // not successful, we'll go straight to the error details. + const graphApiErrors = error.response.body?.error ?? {}; + + errorItem = { + statusCode: error.statusCode, + ...graphApiErrors, + headers: error.response.headers, + }; + } else { + // Unknown Graph API response, we'll dump everything in the response item + errorItem = error; + } + failureItems.push({ json: { ...errorItem }}); + + continue; + } + + if (typeof response === 'string') { + if (this.continueOnFail() === false) { + throw new Error('Response body is not valid JSON.'); + } + + failureItems.push({json: {message: response}}); + continue; + } + + successItems.push({json: response}); + } + + return [successItems, failureItems]; + } +} diff --git a/packages/nodes-base/nodes/Facebook/facebook.png b/packages/nodes-base/nodes/Facebook/facebook.png new file mode 100644 index 0000000000000000000000000000000000000000..b6cba78f88d9da3882f20f1a6d9a212c4fcaf62c GIT binary patch literal 24576 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