Merge pull request #13 from n8n-io/n8n-3857-add-example-node-to-community-repo

Add Example HttpBin Node
This commit is contained in:
Omar Ajoue 2022-06-21 11:26:25 +02:00 committed by GitHub
commit 102187b56e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 551 additions and 21 deletions

2
.eslintignore Normal file
View file

@ -0,0 +1,2 @@
packages/editor-ui
packages/design-system

106
.eslintrc.js Normal file
View file

@ -0,0 +1,106 @@
module.exports = {
root: true,
env: {
browser: true,
es6: true,
node: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
project: ['./tsconfig.json'],
sourceType: 'module',
},
ignorePatterns: [
'.eslintrc.js',
'**/*.js',
'**/node_modules/**',
'**/dist/**',
'**/test/**',
'**/templates/**',
'**/ormconfig.ts',
'**/migrations/**',
],
overrides: [
{
files: [ './**/*.ts' ],
plugins: ['eslint-plugin-n8n-nodes-base'],
rules: {
'n8n-nodes-base/filesystem-wrong-cred-filename': 'error',
'n8n-nodes-base/filesystem-wrong-node-filename': 'error',
'n8n-nodes-base/node-class-description-empty-string': 'error',
'n8n-nodes-base/node-class-description-icon-not-svg': 'error',
'n8n-nodes-base/node-class-description-inputs-wrong-trigger-node': 'error',
'n8n-nodes-base/node-class-description-missing-subtitle': 'error',
'n8n-nodes-base/node-class-description-outputs-wrong': 'error',
'n8n-nodes-base/node-execute-block-double-assertion-for-items': 'error',
'n8n-nodes-base/node-param-collection-type-unsorted-items': 'error',
'n8n-nodes-base/node-param-default-missing': 'error',
'n8n-nodes-base/node-param-default-wrong-for-boolean': 'error',
'n8n-nodes-base/node-param-default-wrong-for-collection': 'error',
'n8n-nodes-base/node-param-default-wrong-for-fixed-collection': 'error',
'n8n-nodes-base/node-param-default-wrong-for-fixed-collection': 'error',
'n8n-nodes-base/node-param-default-wrong-for-multi-options': 'error',
'n8n-nodes-base/node-param-default-wrong-for-number': 'error',
'n8n-nodes-base/node-param-default-wrong-for-simplify': 'error',
'n8n-nodes-base/node-param-default-wrong-for-string': 'error',
'n8n-nodes-base/node-param-description-boolean-without-whether': 'error',
'n8n-nodes-base/node-param-description-comma-separated-hyphen': 'error',
'n8n-nodes-base/node-param-description-empty-string': 'error',
'n8n-nodes-base/node-param-description-excess-final-period': 'error',
'n8n-nodes-base/node-param-description-excess-inner-whitespace': 'error',
'n8n-nodes-base/node-param-description-identical-to-display-name': 'error',
'n8n-nodes-base/node-param-description-line-break-html-tag': 'error',
'n8n-nodes-base/node-param-description-lowercase-first-char': 'error',
'n8n-nodes-base/node-param-description-miscased-id': 'error',
'n8n-nodes-base/node-param-description-miscased-json': 'error',
'n8n-nodes-base/node-param-description-miscased-url': 'error',
'n8n-nodes-base/node-param-description-missing-final-period': 'error',
'n8n-nodes-base/node-param-description-missing-for-ignore-ssl-issues': 'error',
'n8n-nodes-base/node-param-description-missing-for-return-all': 'error',
'n8n-nodes-base/node-param-description-missing-for-simplify': 'error',
'n8n-nodes-base/node-param-description-missing-from-dynamic-options': 'error',
'n8n-nodes-base/node-param-description-missing-from-limit': 'error',
'n8n-nodes-base/node-param-description-unencoded-angle-brackets': 'error',
'n8n-nodes-base/node-param-description-unneeded-backticks': 'error',
'n8n-nodes-base/node-param-description-untrimmed': 'error',
'n8n-nodes-base/node-param-description-url-missing-protocol': 'error',
'n8n-nodes-base/node-param-description-weak': 'error',
'n8n-nodes-base/node-param-description-wrong-for-dynamic-multi-options': 'error',
'n8n-nodes-base/node-param-description-wrong-for-dynamic-options': 'error',
'n8n-nodes-base/node-param-description-wrong-for-ignore-ssl-issues': 'error',
'n8n-nodes-base/node-param-description-wrong-for-limit': 'error',
'n8n-nodes-base/node-param-description-wrong-for-return-all': 'error',
'n8n-nodes-base/node-param-description-wrong-for-simplify': 'error',
'n8n-nodes-base/node-param-description-wrong-for-upsert': 'error',
'n8n-nodes-base/node-param-display-name-excess-inner-whitespace': 'error',
'n8n-nodes-base/node-param-display-name-miscased': 'error',
'n8n-nodes-base/node-param-display-name-miscased-id': 'error',
'n8n-nodes-base/node-param-display-name-untrimmed': 'error',
'n8n-nodes-base/node-param-display-name-wrong-for-dynamic-multi-options': 'error',
'n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options': 'error',
'n8n-nodes-base/node-param-display-name-wrong-for-simplify': 'error',
'n8n-nodes-base/node-param-display-name-wrong-for-update-fields': 'error',
'n8n-nodes-base/node-param-min-value-wrong-for-limit': 'error',
'n8n-nodes-base/node-param-multi-options-type-unsorted-items': 'error',
'n8n-nodes-base/node-param-operation-without-no-data-expression': 'error',
'n8n-nodes-base/node-param-option-description-identical-to-name': 'error',
'n8n-nodes-base/node-param-option-name-containing-star': 'error',
'n8n-nodes-base/node-param-option-name-duplicate': 'error',
'n8n-nodes-base/node-param-option-name-wrong-for-get-all': 'error',
'n8n-nodes-base/node-param-option-name-wrong-for-upsert': 'error',
'n8n-nodes-base/node-param-option-value-duplicate': 'error',
'n8n-nodes-base/node-param-options-type-unsorted-items': 'error',
'n8n-nodes-base/node-param-placeholder-miscased-id': 'error',
'n8n-nodes-base/node-param-placeholder-missing-email': 'error',
'n8n-nodes-base/node-param-required-false': 'error',
'n8n-nodes-base/node-param-resource-with-plural-option': 'error',
'n8n-nodes-base/node-param-resource-without-no-data-expression': 'error',
'n8n-nodes-base/node-param-type-options-missing-from-limit': 'error',
'n8n-nodes-base/node-class-description-inputs-wrong-regular-node': 'error',
},
},
],
};

1
.gitignore vendored
View file

@ -6,3 +6,4 @@ dist
npm-debug.log*
package-lock.json
yarn.lock
.vscode/launch.json

View file

@ -13,6 +13,8 @@ All nodes are npm packages. To make your custom node available to the community,
2. Open the project in your editor.
3. Browse the examples in `/nodes`. Modify the examples, or replace them with your own nodes.
4. Update the `package.json` to match your details.
5. Run `npm run lint` to check for errors or `npm run lintfix` to automatically fix errors when possible.
6. Publish your package to npm. More information on the links below.
## More information

View file

@ -0,0 +1,60 @@
import {
ICredentialDataDecryptedObject,
ICredentialTestRequest,
ICredentialType,
IHttpRequestOptions,
INodeProperties,
} from 'n8n-workflow';
export class HttpBinApi implements ICredentialType {
name = 'httpbinApi';
displayName = 'HttpBin API';
documentationUrl = 'httpbin';
properties: INodeProperties[] = [
{
displayName: 'Token',
name: 'token',
type: 'string',
default: '',
},
// {
// displayName: "API Key",
// name: "apiKey",
// type: "string",
// default: "",
// },
{
displayName: 'Domain',
name: 'domain',
type: 'string',
default: 'https://httpbin.org',
},
];
// authenticate = {
// type: "headerAuth",
// properties: {
// name: "api-key",
// value: "={{$credentials.apiKey}}",
// },
// } as IAuthenticateHeaderAuth;
authenticate = async (
credentials: ICredentialDataDecryptedObject,
requestOptions: IHttpRequestOptions,
): Promise<IHttpRequestOptions> => {
const headers = requestOptions.headers || {};
const authentication = { Authorization: `Bearer ${credentials.token}` };
Object.assign(requestOptions, {
headers: { ...authentication, ...headers },
});
return requestOptions;
};
test: ICredentialTestRequest = {
request: {
baseURL: '={{$credentials?.domain}}',
url: '/bearer',
},
};
}

View file

@ -0,0 +1,21 @@
{
"node": "n8n-nodes-base.httpbin",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": [
"Development",
"Developer Tools"
],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/credentials/httpbin"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/nodes/n8n-nodes-base.httpbin/"
}
]
}
}

View file

@ -0,0 +1,65 @@
/* eslint-disable n8n-nodes-base/filesystem-wrong-node-filename */
import { INodeType, INodeTypeDescription } from 'n8n-workflow';
import { httpVerbFields, httpVerbOperations } from './HttpVerbDescriptions';
export class HttpBin implements INodeType {
description: INodeTypeDescription = {
displayName: 'HttpBin',
name: 'httpbin',
icon: 'file:httpbin.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Interact with HttpBin API',
defaults: {
name: 'HttpBin',
color: '#3b4151',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'httpbinApi',
required: false,
},
],
requestDefaults: {
baseURL: 'https://httpbin.org',
url: '',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
/**
* In the properties array we have two mandatory options objects required
*
* [Resource & Operation]
*
*
* https://docs.n8n.io/integrations/creating-nodes/code/create-first-node/#resources-and-operations
*
* In our example, the operations are separated into their own file (HTTPVerbDescription)
* to keep this class easy to read
*
*/
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'HTTP Verb',
value: 'httpverbs',
},
],
default: 'httpverbs',
},
...httpVerbOperations,
...httpVerbFields,
],
};
}

View file

@ -0,0 +1,246 @@
import { INodeProperties } from 'n8n-workflow';
// This maps the operations to when the Resource option HTTP Verbs is selected
export const httpVerbOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['httpverbs'],
},
},
options: [
{
name: 'GET',
value: 'get',
routing: {
request: {
method: 'GET',
url: '/get',
},
},
},
{
name: 'DELETE',
value: 'delete',
routing: {
request: {
method: 'DELETE',
url: '/delete',
},
},
},
],
default: 'get',
},
];
// Here we define what to show when the GET Operation is selected
// We do that by adding operation: ["get"], to "displayOptions.show"
const getOperation: INodeProperties[] = [
{
name: 'typeofData',
default: 'queryParameter',
description: 'Select type of data to send [Query Parameters]',
displayName: 'Type of Data',
displayOptions: {
show: {
resource: ['httpverbs'],
operation: ['get'],
},
},
type: 'options',
options: [
{
name: 'Query',
value: 'queryParameter',
},
],
required: true,
},
{
name: 'arguments',
default: {},
description: 'The request\'s query parameters',
displayName: 'Query Parameters',
displayOptions: {
show: {
resource: ['httpverbs'],
operation: ['get'],
},
},
options: [
{
name: 'keyvalue',
displayName: 'Key:Value',
values: [
{
displayName: 'Key',
name: 'key',
type: 'string',
default: '',
required: true,
description: 'Key of query parameter',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
routing: {
send: {
property: '={{$parent.key}}',
type: 'query',
},
},
required: true,
description: 'Value of query parameter',
},
],
},
],
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
},
];
// Here we define what to show when the DELETE Operation is selected
// We do that by adding operation: ["delete"], to "displayOptions.show"
const deleteOperation: INodeProperties[] = [
{
name: 'typeofData',
default: 'queryParameter',
description:
'Select type of data to send [Query Parameter Arguments, JSON-Body]',
displayName: 'Type of Data',
displayOptions: {
show: {
resource: ['httpverbs'],
operation: ['delete'],
},
},
options: [
{
name: 'Query',
value: 'queryParameter',
},
{
name: 'JSON',
value: 'jsonData',
},
],
required: true,
type: 'options',
},
{
name: 'arguments',
default: {},
description: 'The request\'s query parameters',
displayName: 'Query Parameters',
displayOptions: {
show: {
resource: ['httpverbs'],
operation: ['delete'],
typeofData: ['queryParameter'],
},
},
options: [
{
name: 'keyvalue',
displayName: 'Key:Value',
values: [
{
displayName: 'Key',
name: 'key',
type: 'string',
default: '',
required: true,
description: 'Key of query parameter',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
routing: {
send: {
property: '={{$parent.key}}',
type: 'query',
},
},
required: true,
description: 'Value of query parameter',
},
],
},
],
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
},
{
name: 'arguments',
default: {},
description: 'The request\'s JSON properties',
displayName: 'JSON Object',
displayOptions: {
show: {
resource: ['httpverbs'],
operation: ['delete'],
typeofData: ['jsonData'],
},
},
options: [
{
name: 'keyvalue',
displayName: 'Key:Value',
values: [
{
displayName: 'Key',
name: 'key',
type: 'string',
default: '',
required: true,
description: 'Key of JSON property',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
routing: {
send: {
property: '={{$parent.key}}',
type: 'body',
},
},
required: true,
description: 'Value of JSON property',
},
],
},
],
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
},
];
export const httpVerbFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* Http Verbs:Get */
/* -------------------------------------------------------------------------- */
...getOperation,
/* -------------------------------------------------------------------------- */
/* Http Verbs:Delete */
/* -------------------------------------------------------------------------- */
...deleteOperation,
];

18
nodes/HttpBin/httpbin.svg Normal file
View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve"> <image id="image0" width="32" height="32" x="0" y="0"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAABGdBTUEAALGPC/xhBQAAACBjSFJN
AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElN
RQfmBg4UAC/TqOZZAAACA0lEQVRIx5XVv09TURwF8M+jFHDSyRkGFhPAEfyRdDHi5uriXyDoYgKT
MJDWzUT/Ahf/AiOEpajEgCESmpiYmDCxGowDTYE+h76+vte+15Zzk753b7733HNO772PbEw7ECba
genswtEcgl0/PHARV72066YrIDSZ6k8KBym4741r0XsB284TdUX8chn1zrzwJUmw4KFXPqjFE0Y0
u5YKEhpmfLZuy7f2wLKGI8WhDRYdaVhurdTCidmU5P44N+skaaGQH1IfFFrOYMotT932zNgQExve
OfTeT8dtBceO3TFlOyopY7UPxV+/fWyn3Y0xrFhJjZWFXhs12pKdRO9ObGSuyB8Xbd9JjMjDc6HQ
IcrKqAiVe8vyCEJPrGBWxZYqqtZt9RbmHabAvAAVdVUlJTvWshbMt0AYn40OmlchSKOePTyYIMQn
rb8yI8TsDCrRs4od7Jv3KOoPGWKboBqp2LN3FQvdO7EPshSsRSTXrSop2cSiiUGkG/bj2JqaQiHW
4nv50mFcu28j30KQarAnEPhuzvwwGYQ975vx7+JwGXTjTIAzoYlhCArR5d0KkfauqJAVY6+FG5hD
OS6veqyCuSiTAQT/jKmlQtyxIBCoZV28HQvN6LuQvJFC4xjvibfYOZUdUXd9taTWJbOubiIVXmjG
W/fs9qpZcpr6pOe1U0udSf8BR7ef4yxyOskAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjItMDYtMTRU
MTc6MDA6NDcrMDM6MDBfo1sRAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDIyLTA2LTE0VDE3OjAwOjQ3
KzAzOjAwLv7jrQAAAABJRU5ErkJggg==" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -19,9 +19,8 @@
"scripts": {
"dev": "npm run watch",
"build": "tsc && gulp",
"lint": "tslint -p tsconfig.json -c tslint.json",
"lintfix": "tslint --fix -p tsconfig.json -c tslint.json",
"nodelinter": "nodelinter",
"lint": "tslint -p tsconfig.json -c tslint.json && node_modules/eslint/bin/eslint.js ./nodes",
"lintfix": "tslint --fix -p tsconfig.json -c tslint.json && node_modules/eslint/bin/eslint.js --fix ./nodes",
"watch": "tsc --watch",
"test": "jest"
},
@ -30,10 +29,12 @@
],
"n8n": {
"credentials": [
"dist/credentials/ExampleCredentials.credentials.js"
"dist/credentials/ExampleCredentials.credentials.js",
"dist/credentials/HttpBinApi.credentials.js"
],
"nodes": [
"dist/nodes/ExampleNode/ExampleNode.node.js"
"dist/nodes/ExampleNode/ExampleNode.node.js",
"dist/nodes/HttpBin/HttpBin.node.js"
]
},
"devDependencies": {
@ -41,10 +42,11 @@
"@types/jest": "^26.0.13",
"@types/node": "^14.17.27",
"@types/request-promise-native": "~1.0.15",
"@typescript-eslint/parser": "^5.29.0",
"eslint-plugin-n8n-nodes-base": "^1.0.43",
"gulp": "^4.0.2",
"jest": "^26.4.2",
"n8n-workflow": "~0.104.0",
"nodelinter": "^0.1.9",
"ts-jest": "^26.3.0",
"tslint": "^6.1.2",
"typescript": "~4.3.5"

View file

@ -17,7 +17,7 @@
"resolveJsonModule": true,
"declaration": true,
"outDir": "./dist/",
"target": "es2017",
"target": "es2019",
"sourceMap": true,
"esModuleInterop": true
},

View file

@ -46,7 +46,11 @@
"forin": true,
"jsdoc-format": true,
"label-position": true,
"indent": [true, "tabs", 2],
"indent": [
true,
"tabs",
2
],
"member-access": [
true,
"no-public"
@ -61,10 +65,13 @@
"no-default-export": true,
"no-duplicate-variable": true,
"no-inferrable-types": true,
"ordered-imports": [true, {
"import-sources-order": "any",
"named-imports-order": "case-insensitive"
}],
"ordered-imports": [
true,
{
"import-sources-order": "any",
"named-imports-order": "case-insensitive"
}
],
"no-namespace": [
true,
"allow-declarations"
@ -90,13 +97,13 @@
"trailing-comma": [
true,
{
"multiline": {
"objects": "always",
"arrays": "always",
"functions": "always",
"typeLiterals": "ignore"
},
"esSpecCompliant": true
"multiline": {
"objects": "always",
"arrays": "always",
"functions": "always",
"typeLiterals": "ignore"
},
"esSpecCompliant": true
}
],
"triple-equals": [