fix(core): Deduplicate error handling in nodes (#4319)

* Fix issue with isAxios property

* 🥅 Deduplicate errors handeling improve errors for credentials

* 🎨 correctly throws error
This commit is contained in:
agobrech 2022-11-11 11:32:43 +01:00 committed by GitHub
parent d35d63a855
commit c7133ecd3f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 50 additions and 187 deletions

View file

@ -39,11 +39,7 @@ export async function actionNetworkApiRequest(
delete options.qs; delete options.qs;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'actionNetworkApi', options); return await this.helpers.requestWithAuthentication.call(this, 'actionNetworkApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export async function handleListing( export async function handleListing(

View file

@ -61,11 +61,7 @@ export async function apiRequest(
delete options.body; delete options.body;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'airtableApi', options); return await this.helpers.requestWithAuthentication.call(this, 'airtableApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
/** /**

View file

@ -7,6 +7,7 @@ import {
IWebhookFunctions, IWebhookFunctions,
} from 'n8n-core'; } from 'n8n-core';
import { IHttpRequestOptions, NodeApiError } from 'n8n-workflow'; import { IHttpRequestOptions, NodeApiError } from 'n8n-workflow';
export async function awsApiRequest( export async function awsApiRequest(
@ -31,11 +32,7 @@ export async function awsApiRequest(
headers, headers,
region: credentials?.region as string, region: credentials?.region as string,
} as IHttpRequestOptions; } as IHttpRequestOptions;
try {
return await this.helpers.requestWithAuthentication.call(this, 'aws', requestOptions); return await this.helpers.requestWithAuthentication.call(this, 'aws', requestOptions);
} catch (error) {
throw new NodeApiError(this.getNode(), error); // no XML parsing needed
}
} }
export async function awsApiRequestREST( export async function awsApiRequestREST(

View file

@ -42,11 +42,7 @@ export async function awsApiRequest(
if (Object.keys(option).length !== 0) { if (Object.keys(option).length !== 0) {
Object.assign(requestOptions, option); Object.assign(requestOptions, option);
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'aws', requestOptions); return await this.helpers.requestWithAuthentication.call(this, 'aws', requestOptions);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export async function awsApiRequestREST( export async function awsApiRequestREST(

View file

@ -40,11 +40,7 @@ export async function awsApiRequest(
if (Object.keys(option).length !== 0) { if (Object.keys(option).length !== 0) {
Object.assign(requestOptions, option); Object.assign(requestOptions, option);
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'aws', requestOptions); return await this.helpers.requestWithAuthentication.call(this, 'aws', requestOptions);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
} }
export async function awsApiRequestREST( export async function awsApiRequestREST(

View file

@ -31,11 +31,7 @@ export async function beeminderApiRequest(
delete options.qs; delete options.qs;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'beeminderApi', options); return await this.helpers.requestWithAuthentication.call(this, 'beeminderApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export async function beeminderApiRequestAllItems( export async function beeminderApiRequestAllItems(

View file

@ -53,11 +53,7 @@ export async function calendlyApiRequest(
delete options.qs; delete options.qs;
} }
options = Object.assign({}, options, option); options = Object.assign({}, options, option);
try {
return await this.helpers.requestWithAuthentication.call(this, 'calendlyApi', options); return await this.helpers.requestWithAuthentication.call(this, 'calendlyApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export function getAuthenticationType(data: string): 'accessToken' | 'apiKey' { export function getAuthenticationType(data: string): 'accessToken' | 'apiKey' {

View file

@ -28,12 +28,7 @@ export async function clockifyApiRequest(
json: true, json: true,
useQuerystring: true, useQuerystring: true,
}; };
try {
return await this.helpers.requestWithAuthentication.call(this, 'clockifyApi', options); return await this.helpers.requestWithAuthentication.call(this, 'clockifyApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export async function clockifyApiRequestAllItems( export async function clockifyApiRequestAllItems(

View file

@ -42,11 +42,7 @@ export async function cortexApiRequest(
delete options.qs; delete options.qs;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'cortexApi', options); return await this.helpers.requestWithAuthentication.call(this, 'cortexApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export function getEntityLabel(entity: IDataObject): string { export function getEntityLabel(entity: IDataObject): string {

View file

@ -32,11 +32,7 @@ export async function customerIoApiRequest(
options.url = `https://beta-api.customer.io/v1/api${endpoint}`; options.url = `https://beta-api.customer.io/v1/api${endpoint}`;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'customerIoApi', options); return await this.helpers.requestWithAuthentication.call(this, 'customerIoApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export function eventExists(currentEvents: string[], webhookEvents: IDataObject) { export function eventExists(currentEvents: string[], webhookEvents: IDataObject) {

View file

@ -30,9 +30,5 @@ export async function dropcontactApiRequest(
delete options.qs; delete options.qs;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'dropcontactApi', options); return await this.helpers.requestWithAuthentication.call(this, 'dropcontactApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }

View file

@ -50,8 +50,7 @@ export async function erpNextApiRequest(
message: 'Please ensure the subdomain is correct.', message: 'Please ensure the subdomain is correct.',
}); });
} }
throw error;
throw new NodeApiError(this.getNode(), error);
} }
} }

View file

@ -44,11 +44,7 @@ export async function ghostApiRequest(
json: true, json: true,
}; };
try {
return await this.helpers.requestWithAuthentication.call(this, credentialType, options); return await this.helpers.requestWithAuthentication.call(this, credentialType, options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
} }
export async function ghostApiRequestAllItems( export async function ghostApiRequestAllItems(

View file

@ -232,13 +232,7 @@ export async function highLevelApiRequest(
delete options.qs; delete options.qs;
} }
options = Object.assign({}, options, option); options = Object.assign({}, options, option);
try {
return await this.helpers.requestWithAuthentication.call(this, 'highLevelApi', options); return await this.helpers.requestWithAuthentication.call(this, 'highLevelApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error, {
message: error.message,
});
}
} }
export async function getPipelineStages( export async function getPipelineStages(

View file

@ -58,11 +58,7 @@ export async function jiraSoftwareCloudApiRequest(
delete options.qs; delete options.qs;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, credentialType, options); return await this.helpers.requestWithAuthentication.call(this, credentialType, options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
} }
export async function jiraSoftwareCloudApiRequestAllItems( export async function jiraSoftwareCloudApiRequestAllItems(

View file

@ -17,10 +17,8 @@ export async function lemlistApiRequest(
qs: IDataObject = {}, qs: IDataObject = {},
option: IDataObject = {}, option: IDataObject = {},
) { ) {
const options: OptionsWithUri = { const options: OptionsWithUri = {
headers: { headers: {},
},
method, method,
uri: `https://api.lemlist.com/api${endpoint}`, uri: `https://api.lemlist.com/api${endpoint}`,
qs, qs,
@ -40,11 +38,7 @@ export async function lemlistApiRequest(
Object.assign(options, option); Object.assign(options, option);
} }
try { return await this.helpers.requestWithAuthentication.call(this, 'lemlistApi', options);
return await this.helpers.requestWithAuthentication.call(this,'lemlistApi',options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
/** /**

View file

@ -48,11 +48,7 @@ export async function mailjetApiRequest(
delete options.body; delete options.body;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, credentialType, options); return await this.helpers.requestWithAuthentication.call(this, credentialType, options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
} }
export async function mailjetApiRequestAllItems( export async function mailjetApiRequestAllItems(

View file

@ -54,10 +54,5 @@ export async function nextCloudApiRequest(
const credentialType = const credentialType =
authenticationMethod === 'accessToken' ? 'nextCloudApi' : 'nextCloudOAuth2Api'; authenticationMethod === 'accessToken' ? 'nextCloudApi' : 'nextCloudOAuth2Api';
try {
return await this.helpers.requestWithAuthentication.call(this, credentialType, options); return await this.helpers.requestWithAuthentication.call(this, credentialType, options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
} }

View file

@ -61,11 +61,7 @@ export async function apiRequest(
delete options.body; delete options.body;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, authenticationMethod, options); return await this.helpers.requestWithAuthentication.call(this, authenticationMethod, options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
/** /**

View file

@ -25,11 +25,7 @@ export async function rocketchatApiRequest(
if (Object.keys(options.body).length === 0) { if (Object.keys(options.body).length === 0) {
delete options.body; delete options.body;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'rocketchatApi', options); return await this.helpers.requestWithAuthentication.call(this, 'rocketchatApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
// tslint:disable-next-line:no-any // tslint:disable-next-line:no-any

View file

@ -36,9 +36,5 @@ export async function segmentApiRequest(
if (!Object.keys(body).length) { if (!Object.keys(body).length) {
delete options.body; delete options.body;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'segmentApi', options); return await this.helpers.requestWithAuthentication.call(this, 'segmentApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }

View file

@ -37,11 +37,7 @@ export async function sendGridApiRequest(
Object.assign(options, option); Object.assign(options, option);
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'sendGridApi', options); return await this.helpers.requestWithAuthentication.call(this, 'sendGridApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export async function sendGridApiRequestAllItems( export async function sendGridApiRequestAllItems(

View file

@ -66,13 +66,9 @@ export async function shopifyApiRequest(
delete options.qs; delete options.qs;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, credentialType, options, { return await this.helpers.requestWithAuthentication.call(this, credentialType, options, {
oauth2: oAuth2Options, oauth2: oAuth2Options,
}); });
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export async function shopifyApiRequestAllItems( export async function shopifyApiRequestAllItems(

View file

@ -29,11 +29,7 @@ export async function stripeApiRequest(
delete options.qs; delete options.qs;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'stripeApi', options); return await this.helpers.requestWithAuthentication.call(this, 'stripeApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
/** /**

View file

@ -40,11 +40,7 @@ export async function theHiveApiRequest(
if (Object.keys(query).length === 0) { if (Object.keys(query).length === 0) {
delete options.qs; delete options.qs;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'theHiveApi', options); return await this.helpers.requestWithAuthentication.call(this, 'theHiveApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
// Helpers functions // Helpers functions

View file

@ -26,14 +26,7 @@ export async function apiRequest(
json: true, json: true,
}; };
try {
return await this.helpers.requestWithAuthentication.call(this, 'trelloApi', options); return await this.helpers.requestWithAuthentication.call(this, 'trelloApi', options);
} catch (error) {
if (error instanceof NodeApiError) {
throw error;
}
throw new NodeApiError(this.getNode(), error as JsonObject);
}
} }
export async function apiRequestAllItems( export async function apiRequestAllItems(

View file

@ -31,12 +31,5 @@ export async function twakeApiRequest(
// options.uri = `${credentials!.hostUrl}/api/v1${resource}`; // options.uri = `${credentials!.hostUrl}/api/v1${resource}`;
// } // }
try {
return await this.helpers.requestWithAuthentication.call(this, 'twakeCloudApi', options); return await this.helpers.requestWithAuthentication.call(this, 'twakeCloudApi', options);
} catch (error) {
if (error.error?.code === 'ECONNREFUSED') {
throw new NodeApiError(this.getNode(), error, { message: 'Twake host is not accessible!' });
}
throw new NodeApiError(this.getNode(), error);
}
} }

View file

@ -36,11 +36,7 @@ export async function twilioApiRequest(
json: true, json: true,
}; };
try {
return await this.helpers.requestWithAuthentication.call(this, 'twilioApi', options); return await this.helpers.requestWithAuthentication.call(this, 'twilioApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
const XML_CHAR_MAP: { [key: string]: string } = { const XML_CHAR_MAP: { [key: string]: string } = {

View file

@ -27,11 +27,7 @@ export async function urlScanIoApiRequest(
delete options.qs; delete options.qs;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'urlScanIoApi', options); return await this.helpers.requestWithAuthentication.call(this, 'urlScanIoApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export async function handleListing( export async function handleListing(

View file

@ -48,11 +48,7 @@ export async function webflowApiRequest(
if (Object.keys(options.body).length === 0) { if (Object.keys(options.body).length === 0) {
delete options.body; delete options.body;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, credentialsType, options); return await this.helpers.requestWithAuthentication.call(this, credentialsType, options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export async function webflowApiRequestAllItems( export async function webflowApiRequestAllItems(

View file

@ -27,12 +27,5 @@ export async function apiRequest(
json: true, json: true,
}; };
try {
return await this.helpers.requestWithAuthentication.call(this, 'wekanApi', options); return await this.helpers.requestWithAuthentication.call(this, 'wekanApi', options);
} catch (error) {
if (error.statusCode === 401) {
throw new NodeOperationError(this.getNode(), 'The Wekan credentials are not valid!');
}
throw new NodeApiError(this.getNode(), error as JsonObject);
}
} }

View file

@ -48,11 +48,7 @@ export async function woocommerceApiRequest(
delete options.form; delete options.form;
} }
options = Object.assign({}, options, option); options = Object.assign({}, options, option);
try {
return await this.helpers.requestWithAuthentication.call(this, 'wooCommerceApi', options); return await this.helpers.requestWithAuthentication.call(this, 'wooCommerceApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
} }
export async function woocommerceApiRequestAllItems( export async function woocommerceApiRequestAllItems(

View file

@ -36,9 +36,5 @@ export async function wufooApiRequest(
delete options.body; delete options.body;
} }
try {
return await this.helpers.requestWithAuthentication.call(this, 'wufooApi', options); return await this.helpers.requestWithAuthentication.call(this, 'wufooApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
} }

View file

@ -48,11 +48,7 @@ export async function zendeskApiRequest(
const credentialType = authenticationMethod === 'apiToken' ? 'zendeskApi' : 'zendeskOAuth2Api'; const credentialType = authenticationMethod === 'apiToken' ? 'zendeskApi' : 'zendeskOAuth2Api';
try {
return await this.helpers.requestWithAuthentication.call(this, credentialType, options); return await this.helpers.requestWithAuthentication.call(this, credentialType, options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
} }
/** /**

View file

@ -255,9 +255,12 @@ const STATUS_CODE_MESSAGES: IStatusCodeMessages = {
'502': 'Bad gateway - the service failed to handle your request', '502': 'Bad gateway - the service failed to handle your request',
'503': 'Service unavailable - perhaps try again later?', '503': 'Service unavailable - perhaps try again later?',
'504': 'Gateway timed out - perhaps try again later?', '504': 'Gateway timed out - perhaps try again later?',
ECONNREFUSED: 'The service refused the connection - perhaps it is offline',
}; };
const UNKNOWN_ERROR_MESSAGE = 'UNKNOWN ERROR - check the detailed error for more information'; const UNKNOWN_ERROR_MESSAGE = 'UNKNOWN ERROR - check the detailed error for more information';
const UNKNOWN_ERROR_MESSAGE_CRED = 'UNKNOWN ERROR';
interface NodeApiErrorOptions extends NodeOperationErrorOptions { interface NodeApiErrorOptions extends NodeOperationErrorOptions {
message?: string; message?: string;
@ -282,10 +285,14 @@ export class NodeApiError extends NodeError {
// only for request library error // only for request library error
this.removeCircularRefs(error.error as JsonObject); this.removeCircularRefs(error.error as JsonObject);
} }
// if it's an error generated by axios // if it's an error generated by axios
// look for descriptions in the response object // look for descriptions in the response object
if (error.isAxiosError && error.response) { if (error.reason) {
error = error.response as JsonObject; const reason: IDataObject = error.reason as unknown as IDataObject;
if (reason.isAxiosError && reason.response) {
error = reason.response as JsonObject;
}
} }
if (message) { if (message) {
@ -351,5 +358,8 @@ export class NodeApiError extends NodeError {
default: default:
this.message = UNKNOWN_ERROR_MESSAGE; this.message = UNKNOWN_ERROR_MESSAGE;
} }
if (this.node.type === 'n8n-nodes-base.noOp' && this.message === UNKNOWN_ERROR_MESSAGE) {
this.message = `${UNKNOWN_ERROR_MESSAGE_CRED} - ${this.httpCode}`;
}
} }
} }