mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(HTTP Request Node): Support for dot notation in JSON body
This commit is contained in:
parent
d87736103d
commit
b29cf9a249
|
@ -1,6 +1,10 @@
|
|||
import type { IDataObject, INodeExecutionData, IOAuth2Options } from 'n8n-workflow';
|
||||
import type { OptionsWithUri } from 'request-promise-native';
|
||||
|
||||
import set from 'lodash.set';
|
||||
|
||||
export type BodyParameter = { name: string; value: string };
|
||||
|
||||
export type IAuthDataSanitizeKeys = {
|
||||
[key: string]: string[];
|
||||
};
|
||||
|
@ -130,3 +134,25 @@ export const binaryContentTypes = [
|
|||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'application/x-7z-compressed',
|
||||
];
|
||||
|
||||
export type BodyParametersReducer = (
|
||||
acc: IDataObject,
|
||||
cur: { name: string; value: string },
|
||||
) => IDataObject;
|
||||
|
||||
export const prepareRequestBody = (
|
||||
parameters: BodyParameter[],
|
||||
bodyType: string,
|
||||
version: number,
|
||||
defaultReducer: BodyParametersReducer,
|
||||
) => {
|
||||
if (bodyType === 'json' && version >= 4) {
|
||||
return parameters.reduce((acc, entry) => {
|
||||
const value = entry.value;
|
||||
set(acc, entry.name, value);
|
||||
return acc;
|
||||
}, {} as IDataObject);
|
||||
} else {
|
||||
return parameters.reduce(defaultReducer, {});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,13 +14,14 @@ export class HttpRequest extends VersionedNodeType {
|
|||
group: ['output'],
|
||||
subtitle: '={{$parameter["requestMethod"] + ": " + $parameter["url"]}}',
|
||||
description: 'Makes an HTTP request and returns the response data',
|
||||
defaultVersion: 3,
|
||||
defaultVersion: 4,
|
||||
};
|
||||
|
||||
const nodeVersions: IVersionedNodeType['nodeVersions'] = {
|
||||
1: new HttpRequestV1(baseDescription),
|
||||
2: new HttpRequestV2(baseDescription),
|
||||
3: new HttpRequestV3(baseDescription),
|
||||
4: new HttpRequestV3(baseDescription),
|
||||
};
|
||||
|
||||
super(nodeVersions, baseDescription);
|
||||
|
|
|
@ -10,14 +10,17 @@ import type {
|
|||
INodeTypeDescription,
|
||||
JsonObject,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { BINARY_ENCODING, jsonParse, NodeApiError, NodeOperationError, sleep } from 'n8n-workflow';
|
||||
|
||||
import type { OptionsWithUri } from 'request-promise-native';
|
||||
|
||||
import type { IAuthDataSanitizeKeys } from '../GenericFunctions';
|
||||
import type { BodyParameter, IAuthDataSanitizeKeys } from '../GenericFunctions';
|
||||
|
||||
import {
|
||||
binaryContentTypes,
|
||||
getOAuth2AdditionalParameters,
|
||||
prepareRequestBody,
|
||||
replaceNullValues,
|
||||
sanitizeUiMessage,
|
||||
} from '../GenericFunctions';
|
||||
|
@ -35,7 +38,7 @@ export class HttpRequestV3 implements INodeType {
|
|||
this.description = {
|
||||
...baseDescription,
|
||||
subtitle: '={{$parameter["method"] + ": " + $parameter["url"]}}',
|
||||
version: 3,
|
||||
version: [3, 4],
|
||||
defaults: {
|
||||
name: 'HTTP Request',
|
||||
color: '#2200DD',
|
||||
|
@ -879,6 +882,7 @@ export class HttpRequestV3 implements INodeType {
|
|||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const nodeVersion = this.getNode().typeVersion;
|
||||
|
||||
const fullResponseProperties = ['body', 'headers', 'statusCode', 'statusMessage'];
|
||||
|
||||
|
@ -960,9 +964,11 @@ export class HttpRequestV3 implements INodeType {
|
|||
const sendBody = this.getNodeParameter('sendBody', itemIndex, false) as boolean;
|
||||
const bodyContentType = this.getNodeParameter('contentType', itemIndex, '') as string;
|
||||
const specifyBody = this.getNodeParameter('specifyBody', itemIndex, '') as string;
|
||||
const bodyParameters = this.getNodeParameter('bodyParameters.parameters', itemIndex, []) as [
|
||||
{ name: string; value: string },
|
||||
];
|
||||
const bodyParameters = this.getNodeParameter(
|
||||
'bodyParameters.parameters',
|
||||
itemIndex,
|
||||
[],
|
||||
) as BodyParameter[];
|
||||
const jsonBodyParameter = this.getNodeParameter('jsonBody', itemIndex, '') as string;
|
||||
const body = this.getNodeParameter('body', itemIndex, '') as string;
|
||||
|
||||
|
@ -1094,7 +1100,12 @@ export class HttpRequestV3 implements INodeType {
|
|||
// Get parameters defined in the UI
|
||||
if (sendBody && bodyParameters) {
|
||||
if (specifyBody === 'keypair' || bodyContentType === 'multipart-form-data') {
|
||||
requestOptions.body = bodyParameters.reduce(parametersToKeyValue, {});
|
||||
requestOptions.body = prepareRequestBody(
|
||||
bodyParameters,
|
||||
bodyContentType,
|
||||
nodeVersion,
|
||||
parametersToKeyValue,
|
||||
);
|
||||
} else if (specifyBody === 'json') {
|
||||
// body is specified using JSON
|
||||
if (typeof jsonBodyParameter !== 'object' && jsonBodyParameter !== null) {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import { prepareRequestBody } from '../../GenericFunctions';
|
||||
import type { BodyParameter, BodyParametersReducer } from '../../GenericFunctions';
|
||||
|
||||
describe('HTTP Node Utils, prepareRequestBody', () => {
|
||||
it('should call default reducer', () => {
|
||||
const bodyParameters: BodyParameter[] = [
|
||||
{
|
||||
name: 'foo.bar',
|
||||
value: 'baz',
|
||||
},
|
||||
];
|
||||
const defaultReducer: BodyParametersReducer = jest.fn();
|
||||
|
||||
prepareRequestBody(bodyParameters, 'json', 3, defaultReducer);
|
||||
|
||||
expect(defaultReducer).toBeCalledTimes(1);
|
||||
expect(defaultReducer).toBeCalledWith({}, { name: 'foo.bar', value: 'baz' }, 0, [
|
||||
{ name: 'foo.bar', value: 'baz' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should call process dot notations', () => {
|
||||
const bodyParameters: BodyParameter[] = [
|
||||
{
|
||||
name: 'foo.bar.spam',
|
||||
value: 'baz',
|
||||
},
|
||||
];
|
||||
const defaultReducer: BodyParametersReducer = jest.fn();
|
||||
|
||||
const result = prepareRequestBody(bodyParameters, 'json', 4, defaultReducer);
|
||||
|
||||
expect(defaultReducer).toBeCalledTimes(0);
|
||||
expect(result).toBeDefined();
|
||||
expect(result).toEqual({ foo: { bar: { spam: 'baz' } } });
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue