UNPKG

@brionmario-experimental/asgardeo-auth-spa

Version:

Asgardeo Auth SPA SDK to be used in Single-Page Applications.

254 lines (227 loc) 9.33 kB
/** * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ import axios from "axios"; import { HttpError, HttpRequestConfig, HttpResponse } from "../.."; import { staticDecorator } from "../helpers"; import { HttpClientInstance, HttpClientInterface, HttpClientStatic } from "../models"; /** * An Http Http client to perform Http requests. * * @remarks * Typescript doesn't support static functions in interfaces. Therefore, * a decorator i.e `staticDecorator` was written to add static support. * Follow {@link https://github.com/Microsoft/TypeScript/issues/13462} * for more info. * * @example * Example usage. * ``` * * const httpClient = HttpClient.getInstance(); * httpClient.init(true, onRequestStart, onRequestSuccess, onRequestError, onRequestFinish); * ``` */ @staticDecorator<HttpClientStatic<HttpClientInstance>>() export class HttpClient implements HttpClientInterface<HttpRequestConfig, HttpResponse, HttpError> { private static axiosInstance: HttpClientInstance; private static clientInstance: HttpClient; private static isHandlerEnabled: boolean; private attachToken: (request: HttpRequestConfig) => Promise<void> = () => Promise.resolve(); private requestStartCallback: (request: HttpRequestConfig) => void = () => null; private requestSuccessCallback: (response: HttpResponse) => void = () => null; private requestErrorCallback: (error: HttpError) => void = () => null; private requestFinishCallback: () => void = () => null; private static readonly DEFAULT_HANDLER_DISABLE_TIMEOUT: number = 1000; /** * Private constructor to avoid object instantiation from outside * the class. * * @hideconstructor */ private constructor() { this.init = this.init.bind(this); this.setHttpRequestErrorCallback = this.setHttpRequestErrorCallback.bind(this); this.setHttpRequestFinishCallback = this.setHttpRequestFinishCallback.bind(this); this.setHttpRequestStartCallback = this.setHttpRequestStartCallback.bind(this); this.setHttpRequestSuccessCallback = this.setHttpRequestSuccessCallback.bind(this); } /** * Returns an aggregated instance of type `HttpInstance` of `HttpClient`. * * @return {any} */ public static getInstance(): HttpClientInstance { if (this.axiosInstance) { return this.axiosInstance; } this.axiosInstance = axios.create({ withCredentials: true }); if (!this.clientInstance) { this.clientInstance = new HttpClient(); } // Register request interceptor this.axiosInstance.interceptors.request.use( async (request) => await this.clientInstance.requestHandler(request) ); // Register response interceptor this.axiosInstance.interceptors.response.use( (response) => this.clientInstance.successHandler(response), (error) => this.clientInstance.errorHandler(error) ); // Add the missing helper methods from axios this.axiosInstance.all = axios.all; this.axiosInstance.spread = axios.spread; // Add the init method from the `HttpClient` instance. this.axiosInstance.init = this.clientInstance.init; // Add the handler enabling & disabling methods to the instance. this.axiosInstance.enableHandler = this.clientInstance.enableHandler; this.axiosInstance.disableHandler = this.clientInstance.disableHandler; this.axiosInstance.disableHandlerWithTimeout = this.clientInstance.disableHandlerWithTimeout; this.axiosInstance.setHttpRequestStartCallback = this.clientInstance.setHttpRequestStartCallback; this.axiosInstance.setHttpRequestSuccessCallback = this.clientInstance.setHttpRequestSuccessCallback; this.axiosInstance.setHttpRequestErrorCallback = this.clientInstance.setHttpRequestErrorCallback; this.axiosInstance.setHttpRequestFinishCallback = this.clientInstance.setHttpRequestFinishCallback; return this.axiosInstance; } /** * Intercepts all the requests. * If the `isHandlerEnabled` flag is set to true, fires the `requestStartCallback` * and retrieves the access token from the server and attaches it to the request. * Else, just returns the original request. * * @param {HttpRequestConfig} request - Original request. * @return {HttpRequestConfig} */ public async requestHandler(request: HttpRequestConfig): Promise<HttpRequestConfig> { await this.attachToken(request); if (request?.shouldEncodeToFormData) { const data = request?.data; const formData = new FormData(); Object.keys(data).forEach((key) => { formData.append(key, data[key]); }); request.data = formData; } request.startTimeInMs = new Date().getTime() if (HttpClient.isHandlerEnabled) { if (this.requestStartCallback && typeof this.requestStartCallback === "function") { this.requestStartCallback(request); } } return request; } /** * Handles response errors. * If the `isHandlerEnabled` flag is set to true, fires the `requestErrorCallback` * and the `requestFinishCallback` functions. Else, just returns the original error. * * @param {HttpError} error - Original error. * @return {HttpError} */ public errorHandler(error: HttpError): HttpError { if (HttpClient.isHandlerEnabled) { if (this.requestErrorCallback && typeof this.requestErrorCallback === "function") { this.requestErrorCallback(error); } if (this.requestFinishCallback && typeof this.requestFinishCallback === "function") { this.requestFinishCallback(); } } throw error; } /** * Handles response success. * If the `isHandlerEnabled` flag is set to true, fires the `requestSuccessCallback` * and the `requestFinishCallback` functions. Else, just returns the original response. * * @param {HttpResponse} response - Original response. * @return {HttpResponse} */ public successHandler(response: HttpResponse): HttpResponse { if (HttpClient.isHandlerEnabled) { if (this.requestSuccessCallback && typeof this.requestSuccessCallback === "function") { this.requestSuccessCallback(response); } if (this.requestFinishCallback && typeof this.requestFinishCallback === "function") { this.requestFinishCallback(); } } return response; } /** * Initializes the Http client. * * @param isHandlerEnabled - Flag to toggle handler enablement. * @param requestStartCallback - Callback function to be triggered on request start. * @param requestSuccessCallback - Callback function to be triggered on request success. * @param requestErrorCallback - Callback function to be triggered on request error. * @param requestFinishCallback - Callback function to be triggered on request error. */ public async init( isHandlerEnabled = true, attachToken: (request: HttpRequestConfig) => Promise<void> ): Promise<void> { HttpClient.isHandlerEnabled = isHandlerEnabled; this.attachToken = attachToken; } /** * Enables the handler. */ public enableHandler(): void { HttpClient.isHandlerEnabled = true; } /** * Disables the handler. */ public disableHandler(): void { HttpClient.isHandlerEnabled = false; } /** * Disables the handler for a given period of time. * * @param {number} timeout - Timeout in milliseconds. */ public disableHandlerWithTimeout(timeout: number = HttpClient.DEFAULT_HANDLER_DISABLE_TIMEOUT): void { HttpClient.isHandlerEnabled = false; setTimeout(() => { HttpClient.isHandlerEnabled = true; }, timeout); } public setHttpRequestStartCallback(callback: () => void): void { this.requestStartCallback = callback; } public setHttpRequestSuccessCallback(callback:(response: HttpResponse)=>void) : void{ this.requestSuccessCallback = callback; } public setHttpRequestErrorCallback(callback:(error: HttpError)=>void) : void { this.requestErrorCallback = callback; } public setHttpRequestFinishCallback(callback:()=>void) : void { this.requestFinishCallback = callback; } }