UNPKG

client-http-api-request-builder

Version:
1 lines 18.1 kB
{"version":3,"sources":["../index.ts","../src/api-builder.ts","../src/request.ts","../src/restEntityApi.ts"],"sourcesContent":["import ApiBuilder, { METHOD_TYPES, DefaultEntityAPIReturnTypes, EndpointsAPIReturnTypes, EntityAPIReturnTypes } from './src/api-builder';\n\nexport { apiRequest as request, toQueryString } from './src/request';\nexport { METHOD_TYPES, DefaultEntityAPIReturnTypes, EndpointsAPIReturnTypes, EntityAPIReturnTypes };\nexport default ApiBuilder;\n","import merge from 'lodash/merge';\nimport RestEntityAPI,{RestEntityAPIReturnTypes} from './restEntityApi';\nimport { AxiosRequestHeaders, RawAxiosRequestHeaders } from 'axios';\n\nconst METHOD_TYPES = {\n POST: 'POST',\n PUT: 'PUT',\n DELETE: 'DELETE',\n GET: 'GET',\n LIST: 'GET',\n};\n\nconst API_METHODS = {\n [METHOD_TYPES.POST]: 'create',\n [METHOD_TYPES.PUT]: 'update',\n [METHOD_TYPES.DELETE]: 'destroy',\n [METHOD_TYPES.GET]: 'getById',\n [METHOD_TYPES.LIST]: 'list',\n};\n\n/**\n *\n * @param {Object} options\n * @param {String} options.name\n * @param {Function}options.endpoint\n * @param {Object} options.endpoints\n * @param {Object} options.entities\n */\n\ninterface ApiBuilderOptions {\n name?: string;\n endpoint?: () => string;\n endpoints?: {\n [x: string]: {\n endpoint: ()=> string;\n type: 'list' | 'create' | 'update' | 'destroy' | 'getById' | string\n }\n };\n entities?: {\n [key: string]: {\n name: string;\n endpoint: ()=> string;\n } };\n headers?: AxiosRequestHeaders | RawAxiosRequestHeaders;\n}\n\ntype UnionToIntersection<U> =\n (U extends any ? (k: U) => void : never) extends ((k: infer I) => void)\n ? I\n : never;\n\ninterface DefaultEntityAPIReturnTypes extends RestEntityAPIReturnTypes{ }\n\n interface EndpointsAPIReturnTypes {\n [key: string]: UnionToIntersection<RestEntityAPIReturnTypes[keyof RestEntityAPIReturnTypes]>;\n}\n interface EntityAPIReturnTypes {\n [key: string]: RestEntityAPIReturnTypes;\n}\n\nconst ApiBuilder = (options: ApiBuilderOptions) => {\n // Destructure the options object to get entities, endpoints, name, endpoint and headers\n const {\n entities, endpoints, name, endpoint, headers,\n } = options;\n // Define a function to get API endpoints\n const getApiEndpoints = (endpoints) => {\n // Initialize an empty object for API endpoints\n let apiEndpoints = {};\n // Initialize an empty object for API entities\n let apiEntities = {};\n\n // Define a function to get methods\n const getMethods = (properties, isEntity, headerOptions) =>\n // Use Object.keys and reduce to iterate over each property\n Object.keys(properties).reduce((methods, methodName) => {\n // Destructure the property to get endpoint, type, and selection\n const { endpoint, type, selection } = properties[methodName];\n // Create a new RestEntityAPI instance\n const api = RestEntityAPI({ name:methodName, endpoint, selection, headers: headerOptions });\n // If isEntity is true, add the entire api instance to methods, otherwise add the specific API method\n\n methods[methodName] = isEntity ? api : api[API_METHODS[type]];\n // Return the updated methods object\n return methods;\n }, {});\n\n // If the name and endpoint are provided in the options\n if (name && endpoint) {\n // Create a new RestEntityAPI instance for the entire entity\n apiEntities = RestEntityAPI({ name, endpoint, headers });\n }\n // If entities are provided and there are entities\n else if (entities && Object.keys(entities).length) {\n // Call getMethods function to get the methods for each entity\n apiEntities = getMethods(entities, true, headers);\n }\n // If endpoints are provided and there are endpoints\n else if (endpoints && Object.keys(endpoints).length) {\n // Call getMethods function to get the methods for each endpoint\n apiEndpoints = getMethods(endpoints, false, headers);\n }\n // Return an object with apiEntities and apiEndpoints\n return merge({}, { ...apiEndpoints }, { ...apiEntities });\n };\n\n // Call getApiEndpoints function to get the API endpoints\n return { ...getApiEndpoints(endpoints)} as DefaultEntityAPIReturnTypes & EndpointsAPIReturnTypes & EntityAPIReturnTypes;\n};\n\nexport { METHOD_TYPES, DefaultEntityAPIReturnTypes, EndpointsAPIReturnTypes, EntityAPIReturnTypes };\nexport default ApiBuilder;\n","import axios, { Method, AxiosRequestHeaders, AxiosResponse, RawAxiosRequestHeaders} from 'axios';\n\nimport isArray from 'lodash/isArray';\nimport reduce from 'lodash/reduce';\nimport replace from 'lodash/replace';\n\n/**\n * Convert api params to query string\n *\n * @param {Object} params Params to convert\n * @return {String}\n */\nexport const toQueryString = (params) =>\n // Use lodash's reduce function to iterate over each key-value pair in the params object\n reduce(\n params,\n (result, value, key) => {\n // If either the key or value is undefined, return the result as is\n if (value === undefined || key === undefined) {\n return result;\n }\n // If the value is an array and it has elements\n if (isArray(value) && value.length > 0) {\n // Use lodash's reduce function to iterate over each item in the value array\n const resultString = reduce(\n value,\n (result, valueItem) => {\n // Replace all occurrences of '#' with '%23' in the valueItem\n valueItem = replace(valueItem, new RegExp('#', 'g'), '%23');\n // Replace all occurrences of apostrophes with '%27' in the valueItem\n valueItem = replace(valueItem, new RegExp('[\\'’]', 'g'), '%27');\n\n // Append the key-value pair to the result string, separated by '&' if result is not empty\n return `${result}${result === '' ? '' : '&'}${key}=${valueItem}`;\n },\n '',\n );\n // Append the resultString to the result, separated by '?' if result is empty, otherwise '&'\n return `${result}${result === '' ? '?' : '&'}${resultString}`;\n }\n\n // If the value is not an array, replace all occurrences of '#' with '%23' and apostrophes with '%27' in the value\n value = replace(value, new RegExp('#', 'g'), '%23');\n value = replace(value, new RegExp('[\\'’]', 'g'), '%27');\n\n // Append the key-value pair to the result, separated by '?' if result is empty, otherwise '&'\n return `${result}${result === '' ? '?' : '&'}${key}=${value}`;\n },\n '',\n );\n\n/**\n * Return headers for network request\n *\n * @param {Object} options\n * @return {Object} headers\n */\nasync function getRequestHeaders(options: RequestOptionTypes) {\n // Define default headers\n const headers = {\n 'Content-Type': 'application/json',\n // Spread operator is used to include any additional headers passed in options\n ...options.headers,\n };\n // Return the headers object\n return headers;\n}\n\n/**\n * Make a request and throw an error if response code is not in successful range.\n *\n * @param {String} url The url of the request.\n * @param {Object} options\n * @param {String} options.method The method for the request.\n * @param {Object} options.headers The headers to send with the request.\n * @param {Object} options.body The body to send with the request.\n */\n\ntype RequestOptionTypes = {\n method?: Method;\n headers?: AxiosRequestHeaders | RawAxiosRequestHeaders;\n body?: any;\n cancelToken?: any;\n formData?: boolean;\n\n}\n\nasync function makeRequest(url: string, options: RequestOptionTypes): Promise<AxiosResponse> {\n let response;\n const requestHeaders = await getRequestHeaders(options);\n const requestOptions = {\n url,\n method: options.method || 'GET',\n headers: Object.entries(requestHeaders).reduce((headers, [key, value]) => {\n headers[key] = value.toString();\n return headers;\n }, {}),\n data: options.body,\n cancelToken: options.cancelToken,\n };\n // If form data is supplied, do not stringify the body and\n // remove the Content-Type header so that the browser can set it itself.\n if (options.formData) {\n requestOptions.headers['Content-Type'] = 'multipart/form-data';\n }\n\n if (options.formData) {\n response = await fetch(url, { body: options.body, ...requestOptions });\n if (response.status < 200 || response.status > 299) {\n throw response;\n }\n const parseResponse = await response.json();\n response = { data: parseResponse };\n }\n else {\n response = await axios(requestOptions);\n }\n\n // Throw an error if the status code is not a successful status code.\n if (response.status < 200 || response.status > 299) {\n throw response;\n }\n\n // Otherwise, return the response.\n return response;\n}\n\n/**\n * Make a request with the ability to refresh tokens in the event of a 401.\n *\n * @param {String} url The url of the request.\n * @param {Object} options\n * @param {Number} retry Retry count\n * @param {String} options.method The method for the request.\n * @param {Object} options.headers The headers to send with the request.\n * @param {Object} options.body The body to send with the request.\n */\nexport async function apiRequest(url:string, options: RequestOptionTypes) {\n try {\n // Make request with current tokens.\n const response = await makeRequest(url, options);\n // Should just return if no-content response\n if (response.status === 204) {\n return true;\n }\n\n return response.data;\n }\n catch (error) {\n const response = error.response || error || {};\n const getEndpoint = (url) =>\n url.substring(\n url.length,\n url.indexOf('?') > -1 ? url.indexOf('?') : undefined,\n );\n const endpoint = url.includes(getEndpoint(url))\n ? getEndpoint(url)\n : 'external endpoint';\n /* eslint-disable-next-line no-underscore-dangle */\n const errorMessage = `Received ${response.status} from ${error?.request?._method} request to ${endpoint}`;\n console.log(`${errorMessage}`, {\n url,\n status: response.status,\n error: response?.data?.error,\n message: response?.data?.message,\n method: options.method,\n headers: options.headers,\n });\n\n throw error;\n }\n}\n","import { apiRequest as request, toQueryString } from './request';\nimport { AxiosRequestHeaders, RawAxiosRequestHeaders } from 'axios';\ntype RestEntityAPIOptions = {\n name: string;\n endpoint: Function;\n selection?: Object;\n headers: AxiosRequestHeaders | RawAxiosRequestHeaders;\n}\n\ninterface CreateTypes {\n data?: any;\n params?: any;\n cancelToken?: any;\n query?: any;\n}\ninterface UpdateTypes {\n id?: any;\n data?: any;\n params?: any;\n}\ninterface DestroyTypes {\n id?: any;\n params?: any;\n}\ninterface GetByIdTypes {\n id?: any;\n params?: any;\n query?: any;\n cancelToken?: any;\n}\ninterface ListTypes {\n query?: any;\n params?: any;\n cancelToken?: any;\n}\n\n\nexport type RestEntityAPIReturnTypes = {\n create: (data?: CreateTypes['data'], params?: CreateTypes['params'], cancelToken?: CreateTypes['cancelToken'], query?: CreateTypes['query']) => Promise<any>;\n update: (id?: UpdateTypes['id'], data?: UpdateTypes['data'], params?: UpdateTypes['params']) => Promise<any>;\n destroy: (id?: DestroyTypes['id'], params?: DestroyTypes['params']) => Promise<any>;\n getById: (id?: GetByIdTypes['id'], params?: GetByIdTypes['params'], query?: GetByIdTypes['query'], cancelToken?: GetByIdTypes['cancelToken']) => Promise<any>;\n list: (query?: ListTypes['query'], params?: ListTypes['params'], cancelToken?: ListTypes['cancelToken']) => Promise<any>;\n buildEndpoint: Function;\n toQueryString: Function;\n} & {}\n\nconst RestEntityAPI = (options:RestEntityAPIOptions): RestEntityAPIReturnTypes => {\n const { endpoint, selection, headers } = options;\n\n const buildEndpoint = (endpoint, params): string =>\n (Array.isArray(params) ? endpoint(...params) : endpoint(params));\n\n const create = async (data, params, cancelToken, query): Promise<any> =>\n request(`${buildEndpoint(endpoint, params)}${toQueryString(query)}`, {\n method: 'POST',\n body: data,\n cancelToken,\n headers,\n ...selection,\n });\n\n const update = async (id, data, params): Promise<any> =>\n request(`${buildEndpoint(endpoint, params)}/${id}`, {\n method: 'PUT',\n body: data,\n headers,\n ...selection,\n });\n\n const destroy = async (id = '', params): Promise<any> =>\n request(`${buildEndpoint(endpoint, params)}/${id}`, {\n method: 'DELETE',\n headers,\n ...selection,\n });\n\n const getById = async (id, params, query = null, cancelToken): Promise<any> =>\n request(\n `${buildEndpoint(endpoint, params)}/${id}${toQueryString(query)}`,\n { method: 'GET', cancelToken },\n );\n\n const list = async (query, params, cancelToken): Promise<any> =>\n request(`${buildEndpoint(endpoint, params)}${toQueryString(query)}`, {\n method: 'GET',\n cancelToken,\n headers,\n ...selection,\n });\n\n return {\n create,\n update,\n destroy,\n getById,\n list,\n buildEndpoint,\n toQueryString,\n };\n};\n\nexport default RestEntityAPI;\n"],"mappings":"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","names":["reduce","isArray","result","replace","axios","url","endpoint","endpoints","endpoint","merge"]}