import { Response } from 'node-fetch'; import { Request } from '../types/request'; import { ErrorData } from '../types/errors'; import { silentlyParseJson } from './silently-parse-json'; import { BadRequestError, UnauthorizedError, PaymentRequiredError, ForbiddenError, NotFoundError, ServerError, UpstreamServiceError } from '../errors'; const _get = require('lodash.get'); function getFullErrorMessage(data: any){ const errorSection = _get(data, 'responseBody.data.error', null); if(errorSection) { const errorArray = _get(errorSection, 'data.responseBody.errors', null); if(errorArray) { let message = errorArray.reduce((acc:any, item:any)=> { const accumulativeMessage = acc ? `${item.message}| ${acc}`: item.message; return accumulativeMessage; }, null); if(data && data.responseBody) { if( data.responseBody.data) { message = `${message} | ${data.responseBody.data.error.message}`; } data.responseBody.message = data.responseBody.message ? `${message} | ${data.responseBody.message}`: message; } } } return data; } /** * Normalise our response errors with the correct information * @param response The response from fetch * @param request The request object * @param targetApiSystemCode the BizOps system code to which the request is being made * @returns An error class for the caller to throw * @example * if (!response.ok) { * throw await responseError(response); * } */ export async function responseError(response: Response, request: Request, targetApiSystemCode?: string) { const responseBody = silentlyParseJson(await response.text()); const status = response.status; const url = request.url; const method = request.method; const tracingHeaders = { 'X-Origin-System-Id': request.headers && request.headers['X-Origin-System-Id'] || '', 'X-Request-Id': request.headers && request.headers['X-Request-Id'] || '', 'X-Origin-User': request.headers && request.headers['X-Origin-User'] || '', }; const data: ErrorData = { url, status, method, responseBody, headers: tracingHeaders }; if (request.body) { data.requestBody = silentlyParseJson(request.body); } if (status == 400) { return new BadRequestError('Bad Request', data); } if (status == 401){ return new UnauthorizedError('Unauthorized', data); } if (status == 402){ return new PaymentRequiredError('Payment Required', data); } if (status == 403){ return new ForbiddenError('Forbidden', data); } if (status == 404){ return new NotFoundError('Not Found', data); } if(status >= 500 && status <= 599){ return new UpstreamServiceError({ code: 'Upstream Service Error', message: 'The membership-sdk has received an error from an upstream service', statusCode: status, relatesToSystems: targetApiSystemCode ? [targetApiSystemCode] : [], ...getFullErrorMessage(data) }); } getFullErrorMessage(data); return new ServerError(`Server Error ${status}`, data); }