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

N8N-3533 Added PostBin node #3236

Merged
merged 11 commits into from
May 27, 2022
5 changes: 4 additions & 1 deletion packages/core/src/NodeExecuteFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,10 @@ function convertN8nRequestToAxios(n8nRequest: IHttpRequestOptions): AxiosRequest
};
}

if (n8nRequest.body) {
// if there is a body and it's empty (does not have properties),
// make sure not to send anything in it as some services fail when
// sending GET request with empty body.
if (n8nRequest.body && Object.keys(n8nRequest.body).length) {
axiosRequest.data = n8nRequest.body;
// Let's add some useful header standards here.
const existingContentTypeHeaderKey = searchForHeader(axiosRequest.headers, 'content-type');
Expand Down
104 changes: 104 additions & 0 deletions packages/nodes-base/nodes/PostBin/BinDescription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import {
INodeProperties
} from 'n8n-workflow';

import {
buildBinAPIURL,
transformBinReponse,
} from './GenericFunctions';


// Operations for the `Bin` resource:
export const binOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'bin',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create bin',
routing: {
request: {
method: 'POST',
url: '/developers/postbin/api/bin',
},
output: {
postReceive: [
transformBinReponse,
],
},
},
},
{
name: 'Get',
value: 'get',
description: 'Get a bin',
routing: {
request: {
method: 'GET',
},
output: {
postReceive: [
transformBinReponse,
],
},
send: {
preSend: [
// Parse binId before sending to make sure it's in the right format
buildBinAPIURL,
],
},
},
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a bin',
routing: {
request: {
method: 'DELETE',
},
send: {
preSend: [
// Parse binId before sending to make sure it's in the right format
buildBinAPIURL,
],
},
},
},
],
default: 'create',
},
];

// Properties of the `Bin` resource
export const binFields: INodeProperties[] = [
{
name: 'binId',
displayName: 'Bin ID',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: [
'bin',
],
operation: [
'get',
'delete',
],
},
},
description: 'Unique identifier for each bin',
},
];
113 changes: 113 additions & 0 deletions packages/nodes-base/nodes/PostBin/GenericFunctions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {
IExecuteSingleFunctions,
IHttpRequestOptions,
IN8nHttpFullResponse,
INodeExecutionData,
NodeApiError,
} from 'n8n-workflow';

// Regular expressions used to extract binId from parameter value
const BIN_ID_REGEX = /\b\d{13}-\d{13}\b/g;

/**
* Creates correctly-formatted PostBin API URL based on the entered binId.
* This function makes sure binId is in the expected format by parsing it
* from current node parameter value.
*
* @export
* @param {IExecuteSingleFunctions} this
* @param {IHttpRequestOptions} requestOptions
* @returns {Promise<IHttpRequestOptions>} requestOptions
*/
export async function buildBinAPIURL(this: IExecuteSingleFunctions, requestOptions: IHttpRequestOptions): Promise<IHttpRequestOptions> {
const binId = parseBinId(this);
// Assemble the PostBin API URL and put it back to requestOptions
requestOptions.url = `/developers/postbin/api/bin/${binId}`;

return requestOptions;
}

/**
* Creates correctly-formatted PostBin Bin test URL based on the entered binId.
* This function makes sure binId is in the expected format by parsing it
* from current node parameter value.
*
* @export
* @param {IExecuteSingleFunctions} this
* @param {IHttpRequestOptions} requestOptions
* @returns {Promise<IHttpRequestOptions>} requestOptions
*/
export async function buildBinTestURL(this: IExecuteSingleFunctions, requestOptions: IHttpRequestOptions): Promise<IHttpRequestOptions> {
const binId = parseBinId(this);

// Assemble the PostBin API URL and put it back to requestOptions
requestOptions.url = `/developers/postbin/${binId}`;
return requestOptions;
}

/**
* Creates correctly-formatted PostBin API URL based on the entered binId and reqId.
* This function makes sure binId is in the expected format by parsing it
* from current node parameter value.
*
* @export
* @param {IExecuteSingleFunctions} this
* @param {IHttpRequestOptions} requestOptions
* @returns {Promise<IHttpRequestOptions>} requestOptions
*/
export async function buildRequestURL(this: IExecuteSingleFunctions, requestOptions: IHttpRequestOptions): Promise<IHttpRequestOptions> {
const reqId = this.getNodeParameter('requestId', 'shift') as string;
const binId = parseBinId(this);

requestOptions.url = `/developers/postbin/api/bin/${binId}/req/${reqId}`;
return requestOptions;
}

/**
* Extracts the PostBin Bin Id from the specified string.
* This method should be able to extract bin Id from the
* PostBin URL or from the string in the following format:
* `Bin '<binId>'.`
*
* @param {IExecuteSingleFunctions} this
* @param {IHttpRequestOptions} requestOptions
* @returns {Promise<IHttpRequestOptions>} requestOptions
*/
function parseBinId(context: IExecuteSingleFunctions) {
const binId = context.getNodeParameter('binId') as string;
// Test if the Bin id is in the expected format
const idMatch = BIN_ID_REGEX.exec(binId);

// Return what is matched
if(idMatch) {
return idMatch[0];
}

// If it's not recognized, error out
throw new NodeApiError(context.getNode(), {}, {
message: 'Bin ID format is not valid',
description: 'Please check the provided Bin ID and try again.',
parseXml: false,
});
}

/**
* Converts the bin response data and adds additional properties
*
* @param {IExecuteSingleFunctions} this
* @param {INodeExecutionData} items[]
* @param {IN8nHttpFullResponse} response
* @returns {Promise<INodeExecutionData[]>}
*/
export async function transformBinReponse(this: IExecuteSingleFunctions, items: INodeExecutionData[], response: IN8nHttpFullResponse): Promise<INodeExecutionData[]> {
items.forEach(item => item.json = {
'binId': item.json.binId,
'nowTimestamp': item.json.now,
'nowIso': new Date(item.json.now as string).toISOString(),
'expiresTimestamp': item.json.expires,
'expiresIso': new Date(item.json.expires as string).toISOString(),
'requestUrl': 'https://www.toptal.com/developers/postbin/' + item.json.binId,
'viewUrl': 'https://www.toptal.com/developers/postbin/b/' + item.json.binId,
});
return items;
}
16 changes: 16 additions & 0 deletions packages/nodes-base/nodes/PostBin/PostBin.node.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"node": "n8n-nodes-base.postbin",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": [
"Development",
"Data & Storage"
],
"resources": {
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/nodes/n8n-nodes-base.postbin/"
}
]
}
}
59 changes: 59 additions & 0 deletions packages/nodes-base/nodes/PostBin/PostBin.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
INodeType,
INodeTypeDescription
} from 'n8n-workflow';

import {
binFields,
binOperations,
} from './BinDescription';

import {
requestFields,
requestOperations,
} from './RequestDescription';

export class PostBin implements INodeType {
description: INodeTypeDescription = {
displayName: 'PostBin',
name: 'postBin',
icon: 'file:postbin.svg',
group: ['transform'],
version: 1,
subtitle: '={{ $parameter["operation"] + ": " + $parameter["resource"] }}',
description: 'Consume PostBin API',
defaults: {
name: 'PostBin',
color: '#4dc0b5',
},
inputs: ['main'],
outputs: ['main'],
credentials: [],
requestDefaults: {
baseURL: 'https://www.toptal.com',
},
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
options: [
{
name: 'Bin',
value: 'bin',
},
{
name: 'Request',
value: 'request',
},
],
default: 'bin',
required: true,
},
...binOperations,
...binFields,
...requestOperations,
...requestFields,
],
};
}
Loading