refactor: Add IRequestOptions type to helpers.request for more type safety (no-changelog) (#8563)

Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
Elias Meire
2024-02-14 16:29:09 +01:00
committed by GitHub
parent 24859cfef5
commit 100d9bc087
330 changed files with 1682 additions and 1492 deletions

View File

@@ -18,10 +18,8 @@ import type {
AxiosError,
AxiosHeaders,
AxiosPromise,
AxiosProxyConfig,
AxiosRequestConfig,
AxiosResponse,
Method,
} from 'axios';
import axios from 'axios';
import crypto, { createHmac } from 'crypto';
@@ -77,6 +75,7 @@ import type {
IOAuth2Options,
IPairedItemData,
IPollFunctions,
IRequestOptions,
IRunExecutionData,
ISourceData,
ITaskData,
@@ -121,8 +120,6 @@ import type { Token } from 'oauth-1.0a';
import clientOAuth1 from 'oauth-1.0a';
import path from 'path';
import { stringify } from 'qs';
import type { OptionsWithUrl } from 'request';
import type { OptionsWithUri, RequestPromiseOptions } from 'request-promise-native';
import { Readable } from 'stream';
import url, { URL, URLSearchParams } from 'url';
@@ -255,7 +252,7 @@ const getHostFromRequestObject = (
}
};
export async function parseRequestObject(requestObject: IDataObject) {
export async function parseRequestObject(requestObject: IRequestOptions) {
// This function is a temporary implementation
// That translates all http requests done via
// the request library to axios directly
@@ -369,28 +366,28 @@ export async function parseRequestObject(requestObject: IDataObject) {
}
if (requestObject.uri !== undefined) {
axiosConfig.url = requestObject.uri?.toString() as string;
axiosConfig.url = requestObject.uri?.toString();
}
if (requestObject.url !== undefined) {
axiosConfig.url = requestObject.url?.toString() as string;
axiosConfig.url = requestObject.url?.toString();
}
if (requestObject.baseURL !== undefined) {
axiosConfig.baseURL = requestObject.baseURL?.toString() as string;
axiosConfig.baseURL = requestObject.baseURL?.toString();
}
if (requestObject.method !== undefined) {
axiosConfig.method = requestObject.method as Method;
axiosConfig.method = requestObject.method;
}
if (requestObject.qs !== undefined && Object.keys(requestObject.qs as object).length > 0) {
axiosConfig.params = requestObject.qs as IDataObject;
axiosConfig.params = requestObject.qs;
}
function hasArrayFormatOptions(
arg: IDataObject,
): arg is IDataObject & { qsStringifyOptions: { arrayFormat: 'repeat' | 'brackets' } } {
arg: IRequestOptions,
): arg is Required<Pick<IRequestOptions, 'qsStringifyOptions'>> {
if (
typeof arg.qsStringifyOptions === 'object' &&
arg.qsStringifyOptions !== null &&
@@ -428,13 +425,13 @@ export async function parseRequestObject(requestObject: IDataObject) {
if (requestObject.auth !== undefined) {
// Check support for sendImmediately
if ((requestObject.auth as IDataObject).bearer !== undefined) {
if (requestObject.auth.bearer !== undefined) {
axiosConfig.headers = Object.assign(axiosConfig.headers || {}, {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
Authorization: `Bearer ${(requestObject.auth as IDataObject).bearer}`,
Authorization: `Bearer ${requestObject.auth.bearer}`,
});
} else {
const authObj = requestObject.auth as IDataObject;
const authObj = requestObject.auth;
// Request accepts both user/username and pass/password
axiosConfig.auth = {
username: (authObj.user || authObj.username) as string,
@@ -506,7 +503,7 @@ export async function parseRequestObject(requestObject: IDataObject) {
axiosConfig.httpsAgent = new Agent(agentOptions);
if (requestObject.timeout !== undefined) {
axiosConfig.timeout = requestObject.timeout as number;
axiosConfig.timeout = requestObject.timeout;
}
if (requestObject.proxy !== undefined) {
@@ -565,7 +562,7 @@ export async function parseRequestObject(requestObject: IDataObject) {
}
}
} else {
axiosConfig.proxy = requestObject.proxy as AxiosProxyConfig;
axiosConfig.proxy = requestObject.proxy;
}
}
@@ -664,12 +661,6 @@ function digestAuthAxiosConfig(
return axiosConfig;
}
type ConfigObject = {
auth?: { sendImmediately: boolean };
resolveWithFullResponse?: boolean;
simple?: boolean;
};
interface IContentType {
type: string;
parameters: {
@@ -762,14 +753,14 @@ export async function proxyRequestToAxios(
workflow: Workflow | undefined,
additionalData: IWorkflowExecuteAdditionalData | undefined,
node: INode | undefined,
uriOrObject: string | object,
options?: object,
uriOrObject: string | IRequestOptions,
options?: IRequestOptions,
): Promise<any> {
let axiosConfig: AxiosRequestConfig = {
maxBodyLength: Infinity,
maxContentLength: Infinity,
};
let configObject: ConfigObject & { uri?: string };
let configObject: IRequestOptions;
if (typeof uriOrObject === 'string') {
configObject = { uri: uriOrObject, ...options };
} else {
@@ -1247,10 +1238,10 @@ async function prepareBinaryData(
}
function applyPaginationRequestData(
requestData: OptionsWithUri,
requestData: IRequestOptions,
paginationRequestData: PaginationOptions['request'],
): OptionsWithUri {
const preparedPaginationData: Partial<OptionsWithUri> = {
): IRequestOptions {
const preparedPaginationData: Partial<IRequestOptions> = {
...paginationRequestData,
uri: paginationRequestData.url,
};
@@ -1269,13 +1260,13 @@ function applyPaginationRequestData(
/**
* Makes a request using OAuth data for authentication
*
* @param {(OptionsWithUri | RequestPromiseOptions)} requestOptions
* @param {(IHttpRequestOptions | IRequestOptions)} requestOptions
*
*/
export async function requestOAuth2(
this: IAllExecuteFunctions,
credentialsType: string,
requestOptions: OptionsWithUri | RequestPromiseOptions | IHttpRequestOptions,
requestOptions: IHttpRequestOptions | IRequestOptions,
node: INode,
additionalData: IWorkflowExecuteAdditionalData,
oAuth2Options?: IOAuth2Options,
@@ -1339,7 +1330,7 @@ export async function requestOAuth2(
oAuth2Options?.tokenType || oauthTokenData.tokenType,
);
(requestOptions as OptionsWithUri).rejectUnauthorized = !credentials.ignoreSSLIssues;
(requestOptions as IRequestOptions).rejectUnauthorized = !credentials.ignoreSSLIssues;
// Signs the request by adding authorization headers or query parameters depending
// on the token-type used.
@@ -1423,7 +1414,7 @@ export async function requestOAuth2(
: oAuth2Options?.tokenExpiredStatusCode;
return await this.helpers
.request(newRequestOptions)
.request(newRequestOptions as IRequestOptions)
.then((response) => {
const requestOptions = newRequestOptions as any;
if (
@@ -1499,7 +1490,7 @@ export async function requestOAuth2(
});
}
return await this.helpers.request(newRequestOptions);
return await this.helpers.request(newRequestOptions as IRequestOptions);
}
// Unknown error so simply throw it
@@ -1513,7 +1504,7 @@ export async function requestOAuth2(
export async function requestOAuth1(
this: IAllExecuteFunctions,
credentialsType: string,
requestOptions: OptionsWithUrl | OptionsWithUri | RequestPromiseOptions | IHttpRequestOptions,
requestOptions: IHttpRequestOptions | IRequestOptions,
isN8nRequest = false,
) {
const credentials = await this.getCredentials(credentialsType);
@@ -1560,25 +1551,24 @@ export async function requestOAuth1(
requestOptions.data = { ...requestOptions.qs, ...requestOptions.form };
// Fixes issue that OAuth1 library only works with "url" property and not with "uri"
// @ts-expect-error @TECH_DEBT: Remove request library
if (requestOptions.uri && !requestOptions.url) {
// @ts-expect-error @TECH_DEBT: Remove request library
if ('uri' in requestOptions && !requestOptions.url) {
requestOptions.url = requestOptions.uri;
// @ts-expect-error @TECH_DEBT: Remove request library
delete requestOptions.uri;
}
requestOptions.headers = oauth.toHeader(
oauth.authorize(requestOptions as unknown as clientOAuth1.RequestOptions, token),
);
) as unknown as Record<string, string>;
if (isN8nRequest) {
return await this.helpers.httpRequest(requestOptions as IHttpRequestOptions);
}
return await this.helpers.request(requestOptions).catch(async (error: IResponseError) => {
// Unknown error so simply throw it
throw error;
});
return await this.helpers
.request(requestOptions as IRequestOptions)
.catch(async (error: IResponseError) => {
// Unknown error so simply throw it
throw error;
});
}
export async function httpRequestWithAuthentication(
@@ -1776,7 +1766,7 @@ export function normalizeItems(
export async function requestWithAuthentication(
this: IAllExecuteFunctions,
credentialsType: string,
requestOptions: OptionsWithUri | RequestPromiseOptions,
requestOptions: IRequestOptions,
workflow: Workflow,
node: INode,
additionalData: IWorkflowExecuteAdditionalData,
@@ -1831,14 +1821,14 @@ export async function requestWithAuthentication(
Object.assign(credentialsDecrypted, data);
}
requestOptions = await additionalData.credentialsHelper.authenticate(
requestOptions = (await additionalData.credentialsHelper.authenticate(
credentialsDecrypted,
credentialsType,
requestOptions as IHttpRequestOptions,
workflow,
node,
);
return await proxyRequestToAxios(workflow, additionalData, node, requestOptions as IDataObject);
)) as IRequestOptions;
return await proxyRequestToAxios(workflow, additionalData, node, requestOptions);
} catch (error) {
try {
if (credentialsDecrypted !== undefined) {
@@ -1855,20 +1845,15 @@ export async function requestWithAuthentication(
// make the updated property in the credentials
// available to the authenticate method
Object.assign(credentialsDecrypted, data);
requestOptions = await additionalData.credentialsHelper.authenticate(
requestOptions = (await additionalData.credentialsHelper.authenticate(
credentialsDecrypted,
credentialsType,
requestOptions as IHttpRequestOptions,
workflow,
node,
);
)) as IRequestOptions;
// retry the request
return await proxyRequestToAxios(
workflow,
additionalData,
node,
requestOptions as IDataObject,
);
return await proxyRequestToAxios(workflow, additionalData, node, requestOptions);
}
}
throw error;
@@ -2849,7 +2834,7 @@ const getRequestHelperFunctions = (
httpRequest,
async requestWithAuthenticationPaginated(
this: IExecuteFunctions,
requestOptions: OptionsWithUri,
requestOptions: IRequestOptions,
itemIndex: number,
paginationOptions: PaginationOptions,
credentialsType?: string,
@@ -3093,7 +3078,7 @@ const getRequestHelperFunctions = (
async requestOAuth1(
this: IAllExecuteFunctions,
credentialsType: string,
requestOptions: OptionsWithUrl | RequestPromiseOptions,
requestOptions: IRequestOptions,
): Promise<any> {
return await requestOAuth1.call(this, credentialsType, requestOptions);
},
@@ -3101,7 +3086,7 @@ const getRequestHelperFunctions = (
async requestOAuth2(
this: IAllExecuteFunctions,
credentialsType: string,
requestOptions: OptionsWithUri | RequestPromiseOptions,
requestOptions: IRequestOptions,
oAuth2Options?: IOAuth2Options,
): Promise<any> {
return await requestOAuth2.call(