UNPKG

integration-websocket-rest-api

Version:

A JavaScript library for easy integration of REST API and WebSocket communication with state management in JS applications.

157 lines (131 loc) 4.46 kB
// installing the required dependencies for the integration of REST API const axios = require("axios"); const moment = require("moment"); const numeral = require("numeral"); // Handle state changes using Redux const { store, apiRequestSuccess, apiRequestFailure, } = require("./state-management-api"); class ApiClient { // Handling the incoming configuration through the constructor constructor(apiUrl, headers = {}) { this.apiUrl = apiUrl; this.headers = headers; this.maxRetries = 3; this.retryDelay = 1000; this.timeout = 5000; this.errorHandler = null; this.requestInterceptors = []; this.responseInterceptors = []; // More configuration options can be added here in future versions } //setters for all the configurations setGlobalHeaders(headers) { this.headers = { ...this.headers, ...headers }; } setMaxRetries(maxRetries) { this.maxRetries = maxRetries; } setRetryDelay(retryDelay) { this.retryDelay = retryDelay; } setTimeout(timeout) { this.timeout = timeout; } setErrorHandler(errorHandler) { this.errorHandler = errorHandler; } addRequestInterceptor(interceptor) { this.requestInterceptors.push(interceptor); } addResponseInterceptor(interceptor) { this.responseInterceptors.push(interceptor); } // Recursive function for deep mapping keys static deepMapKeys(obj, mapFn) { if (Array.isArray(obj)) { return obj.map((item) => ApiClient.deepMapKeys(item, mapFn)); } else if (typeof obj === "object" && obj !== null) { return Object.fromEntries( Object.entries(obj).map(([key, value]) => [ mapFn(value, key), ApiClient.deepMapKeys(value, mapFn), ]) ); } else { return obj; } } // Custom function to convert keys to camelCase static toCamelCase(key) { return key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()); } // Core function to send the axios request to the server async sendRequest(method, data, retryCount = 0) { try { const config = { method, url: this.apiUrl, headers: this.headers, data, timeout: this.timeout, }; // Apply request interceptors if any this.requestInterceptors.forEach((interceptor) => interceptor(config)); const response = await axios(config); // Apply response interceptors if any const modifiedResponse = this.responseInterceptors.reduce( (resp, interceptor) => interceptor(resp), response ); const formattedData = ApiClient.deepMapKeys( modifiedResponse.data, (value, key) => { // Format date strings using moment.js if (moment(value, moment.ISO_8601, true).isValid()) { return moment(value).format("YYYY-MM-DD"); } // Format numbers using numeral.js if (typeof value === "number") { return numeral(value).format("0,0.00"); } // Default: camelCase for other keys return ApiClient.toCamelCase(key); } ); // Dispatch success action store.dispatch(apiRequestSuccess(formattedData)); return formattedData; } catch (error) { if (retryCount < this.maxRetries) { console.log( `Retrying request. Attempt ${retryCount + 1} of ${this.maxRetries}` ); await new Promise((resolve) => setTimeout(resolve, this.retryDelay)); return this.sendRequest(method, data, retryCount + 1); } // Custom error handling if (this.errorHandler) { this.errorHandler(error); } // Dispatch failure action store.dispatch(apiRequestFailure(error)); // Handling errors with user-friendly messages and status codes if (error.response) { // The request was made, but the server responded with a status code outside the range of 2xx throw new Error( `API request failed with status ${error.response.status}: ${error.response.data}` ); } else if (error.request) { // The request was made but no response was received throw new Error(`API request failed: No response received`); } else { // Something happened in setting up the request that triggered an Error throw new Error(`API request setup failed: ${error.message}`); } } } } module.exports = ApiClient;