import axios, { AxiosRequestConfig, AxiosResponse } from 'axios' import { ICaptureResponse } from './CaptureResponse.mjs' import { hasData, isObject } from './general.mjs' import { getHttpHeaderJson } from './AxiosHelper.mjs' import { GrayArrowExceptionHttp } from '../models/GrayArrowException.mjs' import { JSONValue } from '../models/types.mjs' export type HttpMethod = 'DELETE' | 'GET' | 'PATCH' | 'POST' | 'PUT' export type FetchDataTypesAllowed = JSONValue | object | undefined /** * Parameters for making an HTTP call. */ export type HttpFetchRequestProps = { /** * bearerToken An optional security token to add as Authorization to the HTTP header. */ bearerToken?: string /** * The object of the data to pass to the API. */ data?: Tdata /** * An array of HTTP Return Codes that you can use to bypass the standard error handling. * Useful if you want to send back codes like Unauthorized, File too large, ... */ statusCodesToBypassErrorHandler?: number[] } /** * Makes an HTTP call to an API using the given HTTP method. * @param url The URL endpoint of the API call. * @param method The HTTP method to be used. * @param sourceFunctionName The callers function name for outputting in potential error calls. * @param data Optional body to send with the request. Can be a JSON object or a string. * @returns The returned Response object in a Promise. */ export async function fetchHttp( url: string, sourceFunctionName: string, method: HttpMethod, { data, bearerToken }: HttpFetchRequestProps ) { if (!sourceFunctionName || !hasData(sourceFunctionName)) { sourceFunctionName = 'fetchHttp' } if (!hasData(url)) { throw new Error(`${sourceFunctionName} passed an empty URL.`) } let response: AxiosResponse> try { const req: AxiosRequestConfig = { url, method, headers: getHttpHeaderJson(bearerToken), } if (data && hasData(data)) { req.data = isObject(data) ? JSON.stringify(data) : String(data) } response = await axios.request(req) } catch (err) { if (err instanceof GrayArrowExceptionHttp) { throw err } throw new GrayArrowExceptionHttp( err instanceof Error ? err.message : fetchHttp.name, sourceFunctionName ) } if (!response) { throw new GrayArrowExceptionHttp( `${sourceFunctionName}: NO response in HTTP ${method} to URL: ${url}.`, sourceFunctionName ) } if (response.status < 200 || response.status >= 300) { let captureResponse: ICaptureResponse | undefined if (401 === response.status) { try { captureResponse = response.data } catch (jsonerr) { /* empty */ } } throw new GrayArrowExceptionHttp( `${sourceFunctionName}: Error in HTTP ${method} to URL: ${url} with status code ${response.status}.`, sourceFunctionName, { response, captureResponse } ) } return response } export async function fetchData( url: string, sourceFunctionName: string, method: HttpMethod, settings?: HttpFetchRequestProps ) { const resp = await fetchHttp(url, sourceFunctionName, method, settings || {}) return await resp.data } export async function fetchJson( url: string, sourceFunctionName: string, method: HttpMethod, settings?: HttpFetchRequestProps ) { const resp = await fetchHttp(url, sourceFunctionName, method, settings ?? {}) return resp.data } /** * DELETEs data to an API using an HTTP DELETE. * @param url The URL endpoint of the API call. * @param sourceFunctionName The callers function name for outputting in potential error calls. * @param settings The HTTP parameters for making the HTTP call. * @returns The returned Response object in a Promise. */ export async function fetchDelete( url: string, sourceFunctionName: string, settings: HttpFetchRequestProps ) { const resp = await fetchHttp(url, sourceFunctionName, 'DELETE', settings) return resp.data } /** * DELETEs data to an API using an HTTP DELETE. * @param url The URL endpoint of the API call. * @param sourceFunctionName The callers function name for outputting in potential error calls. * @param settings The HTTP parameters for making the HTTP call. * @returns The returned Response object in a Promise. */ export async function fetchDeleteJson( url: string, sourceFunctionName: string, settings: HttpFetchRequestProps ) { return fetchJson(url, sourceFunctionName, 'DELETE', settings) } /** * Fetches data from an API using an HTTP GET. * Returns the JSON data from the API call. * @param url The URL endpoint of the API call. * @param sourceFunctionName The callers function name for outputting in potential error calls. * @param settings The HTTP parameters for making the HTTP call. * @returns The returned JSON object. */ export async function fetchGet( url: string, sourceFunctionName: string, settings?: HttpFetchRequestProps ) { return fetchJson(url, sourceFunctionName, 'GET', settings) } /** * PATCHs data to an API using an HTTP POST. * @param url The URL endpoint of the API call. * @param sourceFunctionName The callers function name for outputting in potential error calls. * @param settings The HTTP parameters for making the HTTP call. * @returns The returned Response object in a Promise. */ export async function fetchPatch( url: string, sourceFunctionName: string, settings: HttpFetchRequestProps ) { return fetchJson(url, sourceFunctionName, 'PATCH', settings) } /** * Fetches data from an API using an HTTP POST. * Returns the JSON data from the API call. * @param url The URL endpoint of the API call. * @param sourceFunctionName The callers function name for outputting in potential error calls. * @param settings The HTTP parameters for making the HTTP call. * @returns The returned JSON object. */ export async function fetchPost( url: string, sourceFunctionName: string, settings?: HttpFetchRequestProps ) { return fetchJson(url, sourceFunctionName, 'POST', settings) } /** * PUTs data to an API using an HTTP POST. * @param url The URL endpoint of the API call. * @param sourceFunctionName The callers function name for outputting in potential error calls. * @param settings The HTTP parameters for making the HTTP call. * @returns The returned Response object in a Promise. */ export async function fetchPut( url: string, sourceFunctionName: string, settings: HttpFetchRequestProps ) { return fetchJson(url, sourceFunctionName, 'PUT', settings) }