/* * Copyright (C) Contributors to the Suwayomi project * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; import storage from '@/util/localStorage.tsx'; export enum HttpMethod { GET = 'get', POST = 'post', PATCH = 'patch', DELETE = 'delete', } type SimpleRestResponse = { data: Data; }; export interface IRestClient { get>(url: string): Promise; delete>(url: string): Promise; post>(url: string, data?: any): Promise; put>(url: string, data?: any): Promise; patch>(url: string, data?: any): Promise; } export class RestClient implements IRestClient { protected client!: AxiosInstance; constructor() { this.createClient(); } public readonly fetcher = async ( url: string, { data, httpMethod = HttpMethod.GET, config, checkResponseIsJson = true, }: { data?: any; httpMethod?: HttpMethod; config?: AxiosRequestConfig; checkResponseIsJson?: boolean; } = {}, ): Promise => { let result: AxiosResponse; switch (httpMethod) { case HttpMethod.GET: result = await this.client[httpMethod](url, config); break; case HttpMethod.POST: case HttpMethod.PATCH: case HttpMethod.DELETE: result = await this.client[httpMethod](url, data, config); break; default: throw new Error(`Unexpected HttpMethod "${httpMethod}"`); } if (result.status !== 200) { throw new Error(result.statusText); } if (checkResponseIsJson && result.headers['content-type'] !== 'application/json') { throw new Error('Response is not json'); } return result.data; }; private createClient(): void { const { hostname, port, protocol } = window.location; // if port is 3000 it's probably running from webpack development server const inferredPort = port === '3000' ? '4567' : port; const baseURL = storage.getItem('serverBaseURL', `${protocol}//${hostname}:${inferredPort}`); this.client = axios.create({ // baseURL must not have trailing slash baseURL, }); this.client.interceptors.request.use((config) => { if (config.data instanceof FormData) { Object.assign(config.headers, { 'Content-Type': 'multipart/form-data' }); } return config; }); } public updateConfig(config: Partial): void { this.client.defaults = { ...this.client.defaults, ...config }; } public getClient(): AxiosInstance { return this.client; } get get() { return this.client.get; } get post() { return this.client.post; } get put() { return this.client.put; } get patch() { return this.client.patch; } get delete() { return this.client.delete; } }