2020-01-10 10:57:01 -08:00
import {
IExecuteFunctions ,
} from 'n8n-core' ;
2019-06-23 03:35:23 -07:00
import {
2020-10-01 05:01:39 -07:00
IBinaryData ,
2019-06-23 03:35:23 -07:00
IDataObject ,
INodeExecutionData ,
INodeType ,
INodeTypeDescription ,
2021-04-16 09:33:36 -07:00
NodeApiError ,
NodeOperationError ,
2019-06-23 03:35:23 -07:00
} from 'n8n-workflow' ;
import { OptionsWithUri } from 'request' ;
interface OptionData {
name : string ;
displayName : string ;
}
interface OptionDataParamters {
[ key : string ] : OptionData ;
}
export class HttpRequest implements INodeType {
description : INodeTypeDescription = {
displayName : 'HTTP Request' ,
name : 'httpRequest' ,
icon : 'fa:at' ,
group : [ 'input' ] ,
version : 1 ,
2019-12-28 19:24:14 -08:00
subtitle : '={{$parameter["requestMethod"] + ": " + $parameter["url"]}}' ,
2021-07-03 05:40:16 -07:00
description : 'Makes an HTTP request and returns the response data' ,
2019-06-23 03:35:23 -07:00
defaults : {
2019-09-04 04:24:44 -07:00
name : 'HTTP Request' ,
2019-06-23 03:35:23 -07:00
color : '#2200DD' ,
} ,
inputs : [ 'main' ] ,
outputs : [ 'main' ] ,
credentials : [
{
name : 'httpBasicAuth' ,
required : true ,
displayOptions : {
show : {
authentication : [
'basicAuth' ,
] ,
} ,
} ,
} ,
2019-09-03 22:37:48 -07:00
{
name : 'httpDigestAuth' ,
required : true ,
displayOptions : {
show : {
authentication : [
'digestAuth' ,
] ,
} ,
} ,
} ,
2019-06-23 03:35:23 -07:00
{
name : 'httpHeaderAuth' ,
required : true ,
displayOptions : {
show : {
authentication : [
'headerAuth' ,
] ,
} ,
} ,
} ,
2021-12-05 08:00:41 -08:00
{
name : 'httpQueryAuth' ,
required : true ,
displayOptions : {
show : {
authentication : [
'queryAuth' ,
] ,
} ,
} ,
} ,
2020-07-25 01:09:52 -07:00
{
name : 'oAuth1Api' ,
required : true ,
displayOptions : {
show : {
authentication : [
'oAuth1' ,
] ,
} ,
} ,
} ,
2020-01-13 18:46:58 -08:00
{
name : 'oAuth2Api' ,
required : true ,
displayOptions : {
show : {
authentication : [
'oAuth2' ,
] ,
} ,
} ,
} ,
2019-06-23 03:35:23 -07:00
] ,
properties : [
{
displayName : 'Authentication' ,
name : 'authentication' ,
type : 'options' ,
options : [
{
name : 'Basic Auth' ,
2020-10-22 06:46:03 -07:00
value : 'basicAuth' ,
2019-06-23 03:35:23 -07:00
} ,
2019-09-03 22:37:48 -07:00
{
name : 'Digest Auth' ,
2020-10-22 06:46:03 -07:00
value : 'digestAuth' ,
2019-09-03 22:37:48 -07:00
} ,
2019-06-23 03:35:23 -07:00
{
name : 'Header Auth' ,
2020-10-22 06:46:03 -07:00
value : 'headerAuth' ,
2019-06-23 03:35:23 -07:00
} ,
2021-12-05 08:00:41 -08:00
{
name : 'Query Auth' ,
value : 'queryAuth' ,
} ,
2020-07-25 01:09:52 -07:00
{
name : 'OAuth1' ,
2020-10-22 06:46:03 -07:00
value : 'oAuth1' ,
2020-07-25 01:09:52 -07:00
} ,
2020-01-13 18:46:58 -08:00
{
name : 'OAuth2' ,
2020-10-22 06:46:03 -07:00
value : 'oAuth2' ,
2020-01-13 18:46:58 -08:00
} ,
2019-06-23 03:35:23 -07:00
{
name : 'None' ,
2020-10-22 06:46:03 -07:00
value : 'none' ,
2019-06-23 03:35:23 -07:00
} ,
] ,
default : 'none' ,
description : 'The way to authenticate.' ,
} ,
{
displayName : 'Request Method' ,
name : 'requestMethod' ,
type : 'options' ,
options : [
{
name : 'DELETE' ,
2020-10-22 06:46:03 -07:00
value : 'DELETE' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'GET' ,
2020-10-22 06:46:03 -07:00
value : 'GET' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'HEAD' ,
2020-10-22 06:46:03 -07:00
value : 'HEAD' ,
2019-06-23 03:35:23 -07:00
} ,
2022-03-25 14:55:43 -07:00
{
name : 'OPTIONS' ,
value : 'OPTIONS' ,
} ,
2019-10-16 03:32:15 -07:00
{
name : 'PATCH' ,
2020-10-22 06:46:03 -07:00
value : 'PATCH' ,
2019-10-16 03:32:15 -07:00
} ,
2019-06-23 03:35:23 -07:00
{
name : 'POST' ,
2020-10-22 06:46:03 -07:00
value : 'POST' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'PUT' ,
2020-10-22 06:46:03 -07:00
value : 'PUT' ,
2019-06-23 03:35:23 -07:00
} ,
] ,
default : 'GET' ,
description : 'The request method to use.' ,
} ,
{
displayName : 'URL' ,
name : 'url' ,
type : 'string' ,
default : '' ,
placeholder : 'http://example.com/index.html' ,
description : 'The URL to make the request to.' ,
required : true ,
} ,
2019-08-13 15:08:45 -07:00
{
displayName : 'Ignore SSL Issues' ,
name : 'allowUnauthorizedCerts' ,
type : 'boolean' ,
default : false ,
description : 'Still download the response even if SSL certificate validation is not possible.' ,
} ,
2019-06-23 03:35:23 -07:00
{
displayName : 'Response Format' ,
name : 'responseFormat' ,
type : 'options' ,
options : [
2019-09-04 04:24:44 -07:00
{
name : 'File' ,
2020-10-22 06:46:03 -07:00
value : 'file' ,
2019-09-04 04:24:44 -07:00
} ,
2019-06-23 03:35:23 -07:00
{
name : 'JSON' ,
2020-10-22 06:46:03 -07:00
value : 'json' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'String' ,
2020-10-22 06:46:03 -07:00
value : 'string' ,
2019-06-23 03:35:23 -07:00
} ,
] ,
default : 'json' ,
description : 'The format in which the data gets returned from the URL.' ,
} ,
2019-09-04 04:24:44 -07:00
{
displayName : 'Property Name' ,
name : 'dataPropertyName' ,
type : 'string' ,
default : 'data' ,
required : true ,
displayOptions : {
show : {
responseFormat : [
'string' ,
] ,
} ,
} ,
description : 'Name of the property to which to write the response data.' ,
} ,
{
displayName : 'Binary Property' ,
name : 'dataPropertyName' ,
type : 'string' ,
default : 'data' ,
required : true ,
displayOptions : {
show : {
responseFormat : [
'file' ,
] ,
} ,
} ,
2021-10-27 13:00:13 -07:00
description : 'Name of the binary property to which to write the data of the read file.' ,
2019-09-04 04:24:44 -07:00
} ,
2019-06-23 03:35:23 -07:00
{
2019-11-02 02:12:59 -07:00
displayName : 'JSON/RAW Parameters' ,
2019-06-23 03:35:23 -07:00
name : 'jsonParameters' ,
type : 'boolean' ,
default : false ,
2019-11-02 13:20:42 -07:00
description : 'If the query and/or body parameter should be set via the value-key pair UI or JSON/RAW.' ,
2019-06-23 03:35:23 -07:00
} ,
2019-09-19 12:56:04 -07:00
{
displayName : 'Options' ,
name : 'options' ,
type : 'collection' ,
placeholder : 'Add Option' ,
default : { } ,
options : [
2020-10-26 05:27:29 -07:00
{
displayName : 'Batch Interval' ,
name : 'batchInterval' ,
type : 'number' ,
typeOptions : {
minValue : 0 ,
} ,
default : 1000 ,
description : 'Time (in milliseconds) between each batch of requests. 0 for disabled.' ,
} ,
{
displayName : 'Batch Size' ,
name : 'batchSize' ,
type : 'number' ,
typeOptions : {
minValue : - 1 ,
} ,
default : 50 ,
description : 'Input will be split in batches to throttle requests. -1 for disabled. 0 will be treated as 1.' ,
} ,
2019-10-16 03:26:47 -07:00
{
displayName : 'Body Content Type' ,
name : 'bodyContentType' ,
type : 'options' ,
displayOptions : {
show : {
'/requestMethod' : [
2019-10-16 03:32:15 -07:00
'PATCH' ,
2019-10-16 03:26:47 -07:00
'POST' ,
'PUT' ,
] ,
} ,
} ,
options : [
{
name : 'JSON' ,
2020-10-22 06:46:03 -07:00
value : 'json' ,
2019-10-16 03:26:47 -07:00
} ,
2019-11-02 02:12:59 -07:00
{
name : 'RAW/Custom' ,
2020-10-22 06:46:03 -07:00
value : 'raw' ,
2019-11-02 02:12:59 -07:00
} ,
2019-10-16 03:26:47 -07:00
{
name : 'Form-Data Multipart' ,
2020-10-22 06:46:03 -07:00
value : 'multipart-form-data' ,
2019-10-16 03:26:47 -07:00
} ,
{
name : 'Form Urlencoded' ,
2020-10-22 06:46:03 -07:00
value : 'form-urlencoded' ,
2019-10-16 03:26:47 -07:00
} ,
] ,
default : 'json' ,
description : 'Content-Type to use to send body parameters.' ,
} ,
2019-09-19 12:56:04 -07:00
{
displayName : 'Full Response' ,
name : 'fullResponse' ,
type : 'boolean' ,
default : false ,
description : 'Returns the full reponse data instead of only the body.' ,
} ,
{
2021-08-08 02:27:07 -07:00
displayName : 'Follow All Redirects' ,
name : 'followAllRedirects' ,
type : 'boolean' ,
default : false ,
description : 'Follow non-GET HTTP 3xx redirects.' ,
} ,
{
displayName : 'Follow GET Redirect' ,
2019-09-19 12:56:04 -07:00
name : 'followRedirect' ,
type : 'boolean' ,
default : true ,
2021-08-08 02:27:07 -07:00
description : 'Follow GET HTTP 3xx redirects.' ,
2019-09-19 12:56:04 -07:00
} ,
{
displayName : 'Ignore Response Code' ,
name : 'ignoreResponseCode' ,
type : 'boolean' ,
default : false ,
description : 'Succeeds also when status code is not 2xx.' ,
} ,
2020-10-26 05:27:29 -07:00
{
displayName : 'MIME Type' ,
name : 'bodyContentCustomMimeType' ,
type : 'string' ,
default : '' ,
placeholder : 'text/xml' ,
description : 'Specify the mime type for raw/custom body type.' ,
required : false ,
displayOptions : {
show : {
'/requestMethod' : [
'PATCH' ,
'POST' ,
'PUT' ,
] ,
} ,
} ,
} ,
2019-09-19 12:56:04 -07:00
{
displayName : 'Proxy' ,
name : 'proxy' ,
type : 'string' ,
default : '' ,
placeholder : 'http://myproxy:3128' ,
description : 'HTTP proxy to use.' ,
} ,
2021-06-23 03:04:50 -07:00
{
displayName : 'Split Into Items' ,
name : 'splitIntoItems' ,
type : 'boolean' ,
default : false ,
description : 'Outputs each element of an array as own item.' ,
displayOptions : {
show : {
'/responseFormat' : [
'json' ,
] ,
} ,
} ,
} ,
2019-09-19 12:56:04 -07:00
{
displayName : 'Timeout' ,
name : 'timeout' ,
type : 'number' ,
typeOptions : {
minValue : 1 ,
} ,
default : 10000 ,
description : 'Time in ms to wait for the server to send response headers (and start the response body) before aborting the request.' ,
} ,
2020-12-29 02:37:06 -08:00
{
displayName : 'Use Querystring' ,
name : 'useQueryString' ,
type : 'boolean' ,
default : false ,
description : 'Set this option to true if you need arrays to be serialized as foo=bar&foo=baz instead of the default foo[0]=bar&foo[1]=baz.' ,
} ,
2019-09-19 12:56:04 -07:00
] ,
} ,
2020-01-10 10:57:01 -08:00
// Body Parameter
2019-06-23 03:35:23 -07:00
{
2020-01-10 10:57:01 -08:00
displayName : 'Send Binary Data' ,
name : 'sendBinaryData' ,
type : 'boolean' ,
displayOptions : {
show : {
// TODO: Make it possible to use dot-notation
// 'options.bodyContentType': [
// 'raw',
// ],
jsonParameters : [
true ,
] ,
requestMethod : [
'PATCH' ,
'POST' ,
'PUT' ,
] ,
} ,
} ,
default : false ,
description : 'If binary data should be send as body.' ,
} ,
{
displayName : 'Binary Property' ,
name : 'binaryPropertyName' ,
type : 'string' ,
required : true ,
default : 'data' ,
displayOptions : {
hide : {
sendBinaryData : [
false ,
] ,
} ,
show : {
jsonParameters : [
true ,
] ,
requestMethod : [
'PATCH' ,
'POST' ,
'PUT' ,
] ,
} ,
} ,
2021-11-25 09:10:06 -08:00
description : ` Name of the binary property which contains the data for the file to be uploaded. For Form-Data Multipart, they can be provided in the format: <code>"sendKey1:binaryProperty1,sendKey2:binaryProperty2</code> ` ,
2020-01-10 10:57:01 -08:00
} ,
{
displayName : 'Body Parameters' ,
name : 'bodyParametersJson' ,
2019-06-23 03:35:23 -07:00
type : 'json' ,
displayOptions : {
2020-01-10 10:57:01 -08:00
hide : {
sendBinaryData : [
true ,
] ,
} ,
2019-06-23 03:35:23 -07:00
show : {
jsonParameters : [
true ,
] ,
2020-01-10 10:57:01 -08:00
requestMethod : [
'PATCH' ,
'POST' ,
'PUT' ,
2022-03-19 12:09:42 -07:00
'DELETE' ,
2020-01-10 10:57:01 -08:00
] ,
2019-06-23 03:35:23 -07:00
} ,
} ,
default : '' ,
2020-01-10 10:57:01 -08:00
description : 'Body parameters as JSON or RAW.' ,
2019-06-23 03:35:23 -07:00
} ,
{
2020-01-10 10:57:01 -08:00
displayName : 'Body Parameters' ,
name : 'bodyParametersUi' ,
placeholder : 'Add Parameter' ,
2019-06-23 03:35:23 -07:00
type : 'fixedCollection' ,
typeOptions : {
multipleValues : true ,
} ,
displayOptions : {
show : {
jsonParameters : [
false ,
] ,
2020-01-10 10:57:01 -08:00
requestMethod : [
'PATCH' ,
'POST' ,
'PUT' ,
2022-03-19 12:09:42 -07:00
'DELETE' ,
2020-01-10 10:57:01 -08:00
] ,
2019-06-23 03:35:23 -07:00
} ,
} ,
2020-01-10 10:57:01 -08:00
description : 'The body parameter to send.' ,
2019-06-23 03:35:23 -07:00
default : { } ,
options : [
{
name : 'parameter' ,
2020-01-10 10:57:01 -08:00
displayName : 'Parameter' ,
2019-06-23 03:35:23 -07:00
values : [
{
displayName : 'Name' ,
name : 'name' ,
type : 'string' ,
default : '' ,
2020-01-10 10:57:01 -08:00
description : 'Name of the parameter.' ,
2019-06-23 03:35:23 -07:00
} ,
{
displayName : 'Value' ,
name : 'value' ,
type : 'string' ,
default : '' ,
2020-01-10 10:57:01 -08:00
description : 'Value of the parameter.' ,
2019-06-23 03:35:23 -07:00
} ,
2020-10-22 06:46:03 -07:00
] ,
2019-06-23 03:35:23 -07:00
} ,
] ,
} ,
2020-01-10 10:57:01 -08:00
// Header Parameters
2019-06-23 03:35:23 -07:00
{
2020-01-10 10:57:01 -08:00
displayName : 'Headers' ,
name : 'headerParametersJson' ,
2019-06-23 03:35:23 -07:00
type : 'json' ,
displayOptions : {
show : {
jsonParameters : [
true ,
] ,
} ,
} ,
default : '' ,
2020-01-10 10:57:01 -08:00
description : 'Header parameters as JSON or RAW.' ,
2019-06-23 03:35:23 -07:00
} ,
{
2020-01-10 10:57:01 -08:00
displayName : 'Headers' ,
name : 'headerParametersUi' ,
placeholder : 'Add Header' ,
2019-06-23 03:35:23 -07:00
type : 'fixedCollection' ,
typeOptions : {
multipleValues : true ,
} ,
displayOptions : {
show : {
jsonParameters : [
false ,
] ,
} ,
} ,
2020-01-10 10:57:01 -08:00
description : 'The headers to send.' ,
2019-06-23 03:35:23 -07:00
default : { } ,
options : [
{
name : 'parameter' ,
2020-01-10 10:57:01 -08:00
displayName : 'Header' ,
2019-06-23 03:35:23 -07:00
values : [
{
displayName : 'Name' ,
name : 'name' ,
type : 'string' ,
default : '' ,
2020-01-10 10:57:01 -08:00
description : 'Name of the header.' ,
2019-06-23 03:35:23 -07:00
} ,
{
displayName : 'Value' ,
name : 'value' ,
type : 'string' ,
default : '' ,
2020-01-10 10:57:01 -08:00
description : 'Value to set for the header.' ,
2019-06-23 03:35:23 -07:00
} ,
2020-10-22 06:46:03 -07:00
] ,
2019-06-23 03:35:23 -07:00
} ,
] ,
} ,
// Query Parameter
{
displayName : 'Query Parameters' ,
name : 'queryParametersJson' ,
type : 'json' ,
displayOptions : {
show : {
jsonParameters : [
true ,
] ,
} ,
} ,
default : '' ,
description : 'Query parameters as JSON (flat object).' ,
} ,
{
displayName : 'Query Parameters' ,
name : 'queryParametersUi' ,
placeholder : 'Add Parameter' ,
type : 'fixedCollection' ,
typeOptions : {
multipleValues : true ,
} ,
displayOptions : {
show : {
jsonParameters : [
false ,
] ,
} ,
} ,
description : 'The query parameter 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.' ,
} ,
2020-10-22 06:46:03 -07:00
] ,
2019-06-23 03:35:23 -07:00
} ,
] ,
} ,
2020-10-22 06:46:03 -07:00
] ,
2019-06-23 03:35:23 -07:00
} ;
async execute ( this : IExecuteFunctions ) : Promise < INodeExecutionData [ ] [ ] > {
const items = this . getInputData ( ) ;
2019-09-19 12:56:04 -07:00
const fullReponseProperties = [
'body' ,
'headers' ,
'statusCode' ,
'statusMessage' ,
] ;
2019-06-23 03:35:23 -07:00
// TODO: Should have a setting which makes clear that this parameter can not change for each item
const requestMethod = this . getNodeParameter ( 'requestMethod' , 0 ) as string ;
const parametersAreJson = this . getNodeParameter ( 'jsonParameters' , 0 ) as boolean ;
2019-09-04 04:24:44 -07:00
const responseFormat = this . getNodeParameter ( 'responseFormat' , 0 ) as string ;
2019-06-23 03:35:23 -07:00
2021-08-20 09:57:30 -07:00
const httpBasicAuth = await this . getCredentials ( 'httpBasicAuth' ) ;
const httpDigestAuth = await this . getCredentials ( 'httpDigestAuth' ) ;
const httpHeaderAuth = await this . getCredentials ( 'httpHeaderAuth' ) ;
2021-12-05 08:00:41 -08:00
const httpQueryAuth = await this . getCredentials ( 'httpQueryAuth' ) ;
2021-08-20 09:57:30 -07:00
const oAuth1Api = await this . getCredentials ( 'oAuth1Api' ) ;
const oAuth2Api = await this . getCredentials ( 'oAuth2Api' ) ;
2019-06-23 03:35:23 -07:00
let requestOptions : OptionsWithUri ;
let setUiParameter : IDataObject ;
const uiParameters : IDataObject = {
bodyParametersUi : 'body' ,
headerParametersUi : 'headers' ,
queryParametersUi : 'qs' ,
} ;
const jsonParameters : OptionDataParamters = {
bodyParametersJson : {
name : 'body' ,
displayName : 'Body Parameters' ,
} ,
headerParametersJson : {
name : 'headers' ,
displayName : 'Headers' ,
} ,
queryParametersJson : {
name : 'qs' ,
displayName : 'Query Paramters' ,
} ,
} ;
2019-08-01 09:22:48 -07:00
const returnItems : INodeExecutionData [ ] = [ ] ;
2020-09-10 06:55:42 -07:00
const requestPromises = [ ] ;
2019-06-23 03:35:23 -07:00
for ( let itemIndex = 0 ; itemIndex < items . length ; itemIndex ++ ) {
2020-03-17 05:18:04 -07:00
const options = this . getNodeParameter ( 'options' , itemIndex , { } ) as IDataObject ;
2019-09-19 12:56:04 -07:00
const url = this . getNodeParameter ( 'url' , itemIndex ) as string ;
2020-10-26 05:27:12 -07:00
if ( itemIndex > 0 && options . batchSize as number >= 0 && options . batchInterval as number > 0 ) {
// defaults batch size to 1 of it's set to 0
const batchSize : number = options . batchSize as number > 0 ? options . batchSize as number : 1 ;
2021-01-06 22:53:48 -08:00
if ( itemIndex % batchSize === 0 ) {
2020-10-26 05:27:29 -07:00
await new Promise ( resolve = > setTimeout ( resolve , options . batchInterval as number ) ) ;
2020-10-26 05:27:12 -07:00
}
}
2019-09-19 12:56:04 -07:00
const fullResponse = ! ! options . fullResponse as boolean ;
2019-06-23 03:35:23 -07:00
requestOptions = {
headers : { } ,
method : requestMethod ,
uri : url ,
2020-01-01 08:28:43 -08:00
gzip : true ,
2019-08-13 15:08:45 -07:00
rejectUnauthorized : ! this . getNodeParameter ( 'allowUnauthorizedCerts' , itemIndex , false ) as boolean ,
2019-06-23 03:35:23 -07:00
} ;
2019-09-19 12:56:04 -07:00
if ( fullResponse === true ) {
// @ts-ignore
requestOptions . resolveWithFullResponse = true ;
}
if ( options . followRedirect !== undefined ) {
requestOptions . followRedirect = options . followRedirect as boolean ;
}
2021-08-08 02:27:07 -07:00
if ( options . followAllRedirects !== undefined ) {
requestOptions . followAllRedirects = options . followAllRedirects as boolean ;
}
2019-09-19 12:56:04 -07:00
if ( options . ignoreResponseCode === true ) {
// @ts-ignore
requestOptions . simple = false ;
}
if ( options . proxy !== undefined ) {
requestOptions . proxy = options . proxy as string ;
}
if ( options . timeout !== undefined ) {
requestOptions . timeout = options . timeout as number ;
2021-04-17 06:15:33 -07:00
} else {
requestOptions . timeout = 3600000 ; // 1 hour
2019-09-19 12:56:04 -07:00
}
2020-12-29 02:37:06 -08:00
if ( options . useQueryString === true ) {
requestOptions . useQuerystring = true ;
}
2019-06-23 03:35:23 -07:00
if ( parametersAreJson === true ) {
// Parameters are defined as JSON
let optionData : OptionData ;
for ( const parameterName of Object . keys ( jsonParameters ) ) {
optionData = jsonParameters [ parameterName ] as OptionData ;
2020-10-14 23:01:30 -07:00
const tempValue = this . getNodeParameter ( parameterName , itemIndex , '' ) as string | object ;
2020-04-08 20:17:02 -07:00
const sendBinaryData = this . getNodeParameter ( 'sendBinaryData' , itemIndex , false ) as boolean ;
2020-01-10 10:57:01 -08:00
if ( optionData . name === 'body' && parametersAreJson === true ) {
if ( sendBinaryData === true ) {
2020-03-23 06:11:29 -07:00
const contentTypesAllowed = [
'raw' ,
'multipart-form-data' ,
] ;
if ( ! contentTypesAllowed . includes ( options . bodyContentType as string ) ) {
2020-01-10 10:57:01 -08:00
// As n8n-workflow.NodeHelpers.getParamterResolveOrder can not be changed
// easily to handle parameters in dot.notation simply error for now.
2021-04-16 09:33:36 -07:00
throw new NodeOperationError ( this . getNode ( ) , 'Sending binary data is only supported when option "Body Content Type" is set to "RAW/CUSTOM" or "FORM-DATA/MULTIPART"!' ) ;
2020-01-10 10:57:01 -08:00
}
const item = items [ itemIndex ] ;
if ( item . binary === undefined ) {
2021-04-16 09:33:36 -07:00
throw new NodeOperationError ( this . getNode ( ) , 'No binary data exists on item!' ) ;
2020-01-10 10:57:01 -08:00
}
2020-03-23 06:11:29 -07:00
if ( options . bodyContentType === 'raw' ) {
2020-03-30 01:31:33 -07:00
const binaryPropertyName = this . getNodeParameter ( 'binaryPropertyName' , itemIndex ) as string ;
if ( item . binary [ binaryPropertyName ] === undefined ) {
2021-04-16 09:33:36 -07:00
throw new NodeOperationError ( this . getNode ( ) , ` No binary data property " ${ binaryPropertyName } " does not exists on item! ` ) ;
2020-03-30 01:31:33 -07:00
}
2022-01-03 13:42:42 -08:00
const binaryDataBuffer = await this . helpers . getBinaryDataBuffer ( itemIndex , binaryPropertyName ) ;
requestOptions . body = binaryDataBuffer ;
2020-03-30 01:31:33 -07:00
} else if ( options . bodyContentType === 'multipart-form-data' ) {
requestOptions . body = { } ;
const binaryPropertyNameFull = this . getNodeParameter ( 'binaryPropertyName' , itemIndex ) as string ;
const binaryPropertyNames = binaryPropertyNameFull . split ( ',' ) . map ( key = > key . trim ( ) ) ;
for ( const propertyData of binaryPropertyNames ) {
let propertyName = 'file' ;
let binaryPropertyName = propertyData ;
if ( propertyData . includes ( ':' ) ) {
const propertyDataParts = propertyData . split ( ':' ) ;
propertyName = propertyDataParts [ 0 ] ;
binaryPropertyName = propertyDataParts [ 1 ] ;
} else if ( binaryPropertyNames . length > 1 ) {
2021-11-25 09:10:06 -08:00
throw new NodeOperationError ( this . getNode ( ) , 'If more than one property should be send it is needed to define the in the format:<code>"sendKey1:binaryProperty1,sendKey2:binaryProperty2"</code>' ) ;
2020-03-30 01:31:33 -07:00
}
if ( item . binary [ binaryPropertyName ] === undefined ) {
2021-04-16 09:33:36 -07:00
throw new NodeOperationError ( this . getNode ( ) , ` No binary data property " ${ binaryPropertyName } " does not exists on item! ` ) ;
2020-03-30 01:31:33 -07:00
}
const binaryProperty = item . binary [ binaryPropertyName ] as IBinaryData ;
2022-01-03 13:42:42 -08:00
const binaryDataBuffer = await this . helpers . getBinaryDataBuffer ( itemIndex , binaryPropertyName ) ;
2020-03-30 01:31:33 -07:00
requestOptions . body [ propertyName ] = {
2022-01-03 13:42:42 -08:00
value : binaryDataBuffer ,
2020-03-30 01:31:33 -07:00
options : {
filename : binaryProperty.fileName ,
contentType : binaryProperty.mimeType ,
} ,
} ;
}
2020-03-23 06:11:29 -07:00
}
2020-01-10 10:57:01 -08:00
continue ;
}
}
2020-10-16 07:05:32 -07:00
if ( tempValue === '' ) {
// Paramter is empty so skip it
continue ;
}
2020-04-13 13:17:23 -07:00
// @ts-ignore
requestOptions [ optionData . name ] = tempValue ;
2019-06-23 03:35:23 -07:00
// @ts-ignore
2019-11-02 02:12:59 -07:00
if ( typeof requestOptions [ optionData . name ] !== 'object' && options . bodyContentType !== 'raw' ) {
// If it is not an object && bodyContentType is not 'raw' it must be JSON so parse it
2019-06-23 03:35:23 -07:00
try {
// @ts-ignore
requestOptions [ optionData . name ] = JSON . parse ( requestOptions [ optionData . name ] ) ;
2021-04-16 09:33:36 -07:00
} catch ( error ) {
throw new NodeOperationError ( this . getNode ( ) , ` The data in " ${ optionData . displayName } " is no valid JSON. Set Body Content Type to "RAW/Custom" for XML or other types of payloads ` ) ;
2019-06-23 03:35:23 -07:00
}
}
}
} else {
// Paramters are defined in UI
let optionName : string ;
for ( const parameterName of Object . keys ( uiParameters ) ) {
setUiParameter = this . getNodeParameter ( parameterName , itemIndex , { } ) as IDataObject ;
optionName = uiParameters [ parameterName ] as string ;
if ( setUiParameter . parameter !== undefined ) {
// @ts-ignore
requestOptions [ optionName ] = { } ;
for ( const parameterData of setUiParameter ! . parameter as IDataObject [ ] ) {
2021-07-10 14:51:35 -07:00
const parameterDataName = parameterData ! . name as string ;
const newValue = parameterData ! . value ;
if ( optionName === 'qs' ) {
const computeNewValue = ( oldValue : unknown ) = > {
if ( typeof oldValue === 'string' ) {
return [ oldValue , newValue ] ;
} else if ( Array . isArray ( oldValue ) ) {
return [ . . . oldValue , newValue ] ;
} else {
return newValue ;
}
} ;
requestOptions [ optionName ] [ parameterDataName ] = computeNewValue ( requestOptions [ optionName ] [ parameterDataName ] ) ;
2022-01-21 01:55:19 -08:00
} else if ( optionName === 'headers' ) {
// @ts-ignore
requestOptions [ optionName ] [ parameterDataName . toString ( ) . toLowerCase ( ) ] = newValue ;
2021-07-10 14:51:35 -07:00
} else {
// @ts-ignore
requestOptions [ optionName ] [ parameterDataName ] = newValue ;
}
2019-06-23 03:35:23 -07:00
}
}
}
}
2019-10-16 03:26:47 -07:00
// Change the way data get send in case a different content-type than JSON got selected
2019-10-16 03:32:15 -07:00
if ( [ 'PATCH' , 'POST' , 'PUT' ] . includes ( requestMethod ) ) {
2019-10-16 03:26:47 -07:00
if ( options . bodyContentType === 'multipart-form-data' ) {
requestOptions . formData = requestOptions . body ;
delete requestOptions . body ;
} else if ( options . bodyContentType === 'form-urlencoded' ) {
requestOptions . form = requestOptions . body ;
delete requestOptions . body ;
}
}
2020-10-19 00:42:04 -07:00
if ( responseFormat === 'file' ) {
requestOptions . encoding = null ;
2021-03-02 01:18:39 -08:00
if ( options . bodyContentType !== 'raw' ) {
requestOptions . body = JSON . stringify ( requestOptions . body ) ;
if ( requestOptions . headers === undefined ) {
requestOptions . headers = { } ;
}
2021-11-12 07:43:39 -08:00
if ( [ 'POST' , 'PUT' , 'PATCH' ] . includes ( requestMethod ) ) {
requestOptions . headers [ 'Content-Type' ] = 'application/json' ;
}
2020-10-19 00:42:04 -07:00
}
} else if ( options . bodyContentType === 'raw' ) {
requestOptions . json = false ;
} else {
requestOptions . json = true ;
}
2019-11-02 02:12:59 -07:00
// Add Content Type if any are set
2019-11-02 13:20:42 -07:00
if ( options . bodyContentCustomMimeType ) {
2021-04-03 07:53:47 -07:00
if ( requestOptions . headers === undefined ) {
2019-11-02 02:12:59 -07:00
requestOptions . headers = { } ;
}
2019-11-02 13:20:42 -07:00
requestOptions . headers [ 'Content-Type' ] = options . bodyContentCustomMimeType ;
2019-11-02 02:12:59 -07:00
}
2019-06-23 03:35:23 -07:00
// Add credentials if any are set
if ( httpBasicAuth !== undefined ) {
requestOptions . auth = {
user : httpBasicAuth.user as string ,
pass : httpBasicAuth.password as string ,
} ;
}
if ( httpHeaderAuth !== undefined ) {
requestOptions . headers ! [ httpHeaderAuth . name as string ] = httpHeaderAuth . value ;
}
2021-12-05 08:00:41 -08:00
if ( httpQueryAuth !== undefined ) {
if ( ! requestOptions . qs ) {
requestOptions . qs = { } ;
}
requestOptions . qs ! [ httpQueryAuth . name as string ] = httpQueryAuth . value ;
}
2019-09-03 22:37:48 -07:00
if ( httpDigestAuth !== undefined ) {
requestOptions . auth = {
user : httpDigestAuth.user as string ,
pass : httpDigestAuth.password as string ,
sendImmediately : false ,
} ;
}
2019-06-23 03:35:23 -07:00
2020-08-28 08:42:35 -07:00
if ( requestOptions . headers ! [ 'accept' ] === undefined ) {
if ( responseFormat === 'json' ) {
requestOptions . headers ! [ 'accept' ] = 'application/json,text/*;q=0.99' ;
} else if ( responseFormat === 'string' ) {
requestOptions . headers ! [ 'accept' ] = 'application/json,text/html,application/xhtml+xml,application/xml,text/*;q=0.9, */*;q=0.1' ;
} else {
requestOptions . headers ! [ 'accept' ] = 'application/json,text/html,application/xhtml+xml,application/xml,text/*;q=0.9, image/*;q=0.8, */*;q=0.7' ;
}
2020-01-01 08:28:43 -08:00
}
2021-06-12 11:22:55 -07:00
try {
2021-06-12 11:24:13 -07:00
let sendRequest : any = requestOptions ; // tslint:disable-line:no-any
2021-06-12 11:22:55 -07:00
// Protect browser from sending large binary data
if ( Buffer . isBuffer ( sendRequest . body ) && sendRequest . body . length > 250000 ) {
sendRequest = {
. . . requestOptions ,
body : ` Binary data got replaced with this text. Original was a Buffer with a size of ${ requestOptions . body . length } byte. ` ,
} ;
}
this . sendMessageToUI ( sendRequest ) ;
2021-11-12 07:43:39 -08:00
} catch ( e ) { }
2021-06-12 11:22:55 -07:00
2020-09-10 06:55:42 -07:00
// Now that the options are all set make the actual http request
if ( oAuth1Api !== undefined ) {
requestPromises . push ( this . helpers . requestOAuth1 . call ( this , 'oAuth1Api' , requestOptions ) ) ;
} else if ( oAuth2Api !== undefined ) {
requestPromises . push ( this . helpers . requestOAuth2 . call ( this , 'oAuth2Api' , requestOptions , { tokenType : 'Bearer' } ) ) ;
} else {
requestPromises . push ( this . helpers . request ( requestOptions ) ) ;
}
}
// @ts-ignore
const promisesResponses = await Promise . allSettled ( requestPromises ) ;
let response : any ; // tslint:disable-line:no-any
for ( let itemIndex = 0 ; itemIndex < items . length ; itemIndex ++ ) {
// @ts-ignore
response = promisesResponses . shift ( ) ;
if ( response ! . status !== 'fulfilled' ) {
if ( this . continueOnFail ( ) !== true ) {
// throw error;
2021-04-16 09:33:36 -07:00
throw new NodeApiError ( this . getNode ( ) , response ) ;
2020-04-04 08:34:10 -07:00
} else {
2020-09-10 06:55:42 -07:00
// Return the actual reason as error
returnItems . push (
{
json : {
error : response.reason ,
} ,
2020-10-22 09:00:28 -07:00
} ,
2020-09-10 06:55:42 -07:00
) ;
2020-03-17 05:18:04 -07:00
continue ;
}
2020-01-13 18:46:58 -08:00
}
2019-06-23 03:35:23 -07:00
2020-09-10 06:55:42 -07:00
response = response . value ;
const options = this . getNodeParameter ( 'options' , itemIndex , { } ) as IDataObject ;
const url = this . getNodeParameter ( 'url' , itemIndex ) as string ;
const fullResponse = ! ! options . fullResponse as boolean ;
2019-09-04 04:24:44 -07:00
if ( responseFormat === 'file' ) {
const dataPropertyName = this . getNodeParameter ( 'dataPropertyName' , 0 ) as string ;
const newItem : INodeExecutionData = {
2019-09-19 12:56:04 -07:00
json : { } ,
2019-09-04 04:24:44 -07:00
binary : { } ,
} ;
if ( items [ itemIndex ] . binary !== undefined ) {
// Create a shallow copy of the binary data so that the old
// data references which do not get changed still stay behind
// but the incoming data does not get changed.
Object . assign ( newItem . binary , items [ itemIndex ] . binary ) ;
}
const fileName = ( url ) . split ( '/' ) . pop ( ) ;
2019-09-19 12:56:04 -07:00
if ( fullResponse === true ) {
const returnItem : IDataObject = { } ;
for ( const property of fullReponseProperties ) {
if ( property === 'body' ) {
continue ;
}
2021-04-03 07:53:47 -07:00
returnItem [ property ] = response ! [ property ] ;
2019-09-19 12:56:04 -07:00
}
newItem . json = returnItem ;
2020-09-10 06:55:42 -07:00
newItem . binary ! [ dataPropertyName ] = await this . helpers . prepareBinaryData ( response ! . body , fileName ) ;
2019-09-19 12:56:04 -07:00
} else {
newItem . json = items [ itemIndex ] . json ;
2020-09-10 06:55:42 -07:00
newItem . binary ! [ dataPropertyName ] = await this . helpers . prepareBinaryData ( response ! , fileName ) ;
2019-09-19 12:56:04 -07:00
}
2020-12-25 13:59:22 -08:00
returnItems . push ( newItem ) ;
2019-09-04 13:02:10 -07:00
} else if ( responseFormat === 'string' ) {
2019-09-04 04:24:44 -07:00
const dataPropertyName = this . getNodeParameter ( 'dataPropertyName' , 0 ) as string ;
2019-09-19 12:56:04 -07:00
if ( fullResponse === true ) {
const returnItem : IDataObject = { } ;
for ( const property of fullReponseProperties ) {
if ( property === 'body' ) {
2020-09-10 06:55:42 -07:00
returnItem [ dataPropertyName ] = response ! [ property ] ;
2019-09-19 12:56:04 -07:00
continue ;
}
2020-09-10 06:55:42 -07:00
returnItem [ property ] = response ! [ property ] ;
2019-09-04 04:24:44 -07:00
}
2019-09-19 12:56:04 -07:00
returnItems . push ( { json : returnItem } ) ;
} else {
returnItems . push ( {
json : {
[ dataPropertyName ] : response ,
2020-04-09 15:44:09 -07:00
} ,
2019-09-19 12:56:04 -07:00
} ) ;
}
2019-06-23 03:35:23 -07:00
} else {
2019-09-04 13:41:17 -07:00
// responseFormat: 'json'
2019-09-19 12:56:04 -07:00
if ( fullResponse === true ) {
const returnItem : IDataObject = { } ;
for ( const property of fullReponseProperties ) {
2020-09-10 06:55:42 -07:00
returnItem [ property ] = response ! [ property ] ;
2019-09-19 12:56:04 -07:00
}
2020-04-09 15:44:09 -07:00
if ( responseFormat === 'json' && typeof returnItem . body === 'string' ) {
try {
returnItem . body = JSON . parse ( returnItem . body ) ;
2021-04-16 09:33:36 -07:00
} catch ( error ) {
throw new NodeOperationError ( this . getNode ( ) , 'Response body is not valid JSON. Change "Response Format" to "String"' ) ;
2020-04-09 15:44:09 -07:00
}
2019-09-19 12:56:04 -07:00
}
returnItems . push ( { json : returnItem } ) ;
} else {
2020-04-09 15:44:09 -07:00
if ( responseFormat === 'json' && typeof response === 'string' ) {
try {
response = JSON . parse ( response ) ;
2021-04-16 09:33:36 -07:00
} catch ( error ) {
throw new NodeOperationError ( this . getNode ( ) , 'Response body is not valid JSON. Change "Response Format" to "String"' ) ;
2020-04-09 15:44:09 -07:00
}
2019-09-19 12:56:04 -07:00
}
2021-06-23 03:04:50 -07:00
if ( options . splitIntoItems === true && Array . isArray ( response ) ) {
response . forEach ( item = > returnItems . push ( { json : item } ) ) ;
} else {
returnItems . push ( { json : response } ) ;
}
2019-09-19 12:56:04 -07:00
}
2019-06-23 03:35:23 -07:00
}
}
2020-12-25 13:59:22 -08:00
return this . prepareOutputData ( returnItems ) ;
2019-06-23 03:35:23 -07:00
}
2021-10-27 13:00:13 -07:00
}