123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- import { addLogLine } from "@ente/shared/logging";
- import { logError } from "@ente/shared/sentry";
- import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
- import { ApiError, CustomError, isApiErrorResponse } from "../error";
- interface IHTTPHeaders {
- [headerKey: string]: any;
- }
- interface IQueryPrams {
- [paramName: string]: any;
- }
- /**
- * Service to manage all HTTP calls.
- */
- class HTTPService {
- constructor() {
- axios.interceptors.response.use(
- (response) => Promise.resolve(response),
- (error) => {
- const config = error.config as AxiosRequestConfig;
- if (error.response) {
- const response = error.response as AxiosResponse;
- let apiError: ApiError;
- // The request was made and the server responded with a status code
- // that falls out of the range of 2xx
- if (isApiErrorResponse(response.data)) {
- const responseData = response.data;
- logError(error, "HTTP Service Error", {
- url: config.url,
- method: config.method,
- xRequestId: response.headers["x-request-id"],
- httpStatus: response.status,
- errMessage: responseData.message,
- errCode: responseData.code,
- });
- apiError = new ApiError(
- responseData.message,
- responseData.code,
- response.status,
- );
- } else {
- if (response.status >= 400 && response.status < 500) {
- apiError = new ApiError(
- CustomError.CLIENT_ERROR,
- "",
- response.status,
- );
- } else {
- apiError = new ApiError(
- CustomError.ServerError,
- "",
- response.status,
- );
- }
- }
- logError(apiError, "HTTP Service Error", {
- url: config.url,
- method: config.method,
- cfRay: response.headers["cf-ray"],
- xRequestId: response.headers["x-request-id"],
- httpStatus: response.status,
- });
- throw apiError;
- } else if (error.request) {
- // The request was made but no response was received
- // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
- // http.ClientRequest in node.js
- addLogLine(
- "request failed- no response",
- `url: ${config.url}`,
- `method: ${config.method}`,
- );
- return Promise.reject(error);
- } else {
- // Something happened in setting up the request that triggered an Error
- addLogLine(
- "request failed- axios error",
- `url: ${config.url}`,
- `method: ${config.method}`,
- );
- return Promise.reject(error);
- }
- },
- );
- }
- /**
- * header object to be append to all api calls.
- */
- private headers: IHTTPHeaders = {
- "content-type": "application/json",
- };
- /**
- * Sets the headers to the given object.
- */
- public setHeaders(headers: IHTTPHeaders) {
- this.headers = {
- ...this.headers,
- ...headers,
- };
- }
- /**
- * Adds a header to list of headers.
- */
- public appendHeader(key: string, value: string) {
- this.headers = {
- ...this.headers,
- [key]: value,
- };
- }
- /**
- * Removes the given header.
- */
- public removeHeader(key: string) {
- this.headers[key] = undefined;
- }
- /**
- * Returns axios interceptors.
- */
- // eslint-disable-next-line class-methods-use-this
- public getInterceptors() {
- return axios.interceptors;
- }
- /**
- * Generic HTTP request.
- * This is done so that developer can use any functionality
- * provided by axios. Here, only the set headers are spread
- * over what was sent in config.
- */
- public async request(config: AxiosRequestConfig, customConfig?: any) {
- // eslint-disable-next-line no-param-reassign
- config.headers = {
- ...this.headers,
- ...config.headers,
- };
- if (customConfig?.cancel) {
- config.cancelToken = new axios.CancelToken(
- (c) => (customConfig.cancel.exec = c),
- );
- }
- return await axios({ ...config, ...customConfig });
- }
- /**
- * Get request.
- */
- public get(
- url: string,
- params?: IQueryPrams,
- headers?: IHTTPHeaders,
- customConfig?: any,
- ) {
- return this.request(
- {
- headers,
- method: "GET",
- params,
- url,
- },
- customConfig,
- );
- }
- /**
- * Post request
- */
- public post(
- url: string,
- data?: any,
- params?: IQueryPrams,
- headers?: IHTTPHeaders,
- customConfig?: any,
- ) {
- return this.request(
- {
- data,
- headers,
- method: "POST",
- params,
- url,
- },
- customConfig,
- );
- }
- /**
- * Patch request
- */
- public patch(
- url: string,
- data?: any,
- params?: IQueryPrams,
- headers?: IHTTPHeaders,
- customConfig?: any,
- ) {
- return this.request(
- {
- data,
- headers,
- method: "PATCH",
- params,
- url,
- },
- customConfig,
- );
- }
- /**
- * Put request
- */
- public put(
- url: string,
- data: any,
- params?: IQueryPrams,
- headers?: IHTTPHeaders,
- customConfig?: any,
- ) {
- return this.request(
- {
- data,
- headers,
- method: "PUT",
- params,
- url,
- },
- customConfig,
- );
- }
- /**
- * Delete request
- */
- public delete(
- url: string,
- data: any,
- params?: IQueryPrams,
- headers?: IHTTPHeaders,
- customConfig?: any,
- ) {
- return this.request(
- {
- data,
- headers,
- method: "DELETE",
- params,
- url,
- },
- customConfig,
- );
- }
- }
- // Creates a Singleton Service.
- // This will help me maintain common headers / functionality
- // at a central place.
- export default new HTTPService();
|