import request, { Agent } from "superagent"; import prefix from "superagent-prefix"; export function customErrorHandler(err: Error): request.Response { // optional chaining doesn't work in repos that don't use node-ts yet. const errMsg = (err as any) && (err as any).response && (err as any).response.text? (err as any).response.text: err.message; throw new Error(errMsg); } export abstract class BaseCaller { /** * Makes the request after prefixing the apiUrl to the request path * https://visionmedia.github.io/superagent/#get-requests */ protected agent: Agent; /** * base API url */ protected apiUrl: string; /** * Used in case we use the default token used at the time this class was initialized */ private authTokenString: string | undefined; /** * In case the caller decides to pass a function to use to get the authToken */ private authTokenFunction: (() => string) | undefined; protected useBearerToken = true; /** * Used in case we pass a function to resolve the authToken at realTime * By default, this simply returns the passed authToken */ protected getAuthToken = (): string => { if (this.authTokenString !== undefined) { if(this.useBearerToken) { if(!this.authTokenString.startsWith("Bearer ")){ return `Bearer ${this.authTokenString}` } } return `${this.authTokenString}`; } else if (this.authTokenFunction !== undefined) { return this.authTokenFunction(); } else { console.log(`Error from BaseCaller: no auth token set`); return ""; } } /** * Used for callers where the only option is to use API token * Can be used in the Caller code instead of calling callerInstance.setUseBearerToken(false) in the implementation file * which would set the Bearer option globally for this callerInstance */ protected getApiToken = (): string => { if (this.authTokenString !== undefined) { return `${this.authTokenString}`; } else { console.log(`Error from BaseCaller: no auth token set`); return ""; } } private setAuthToken(authToken: string | (() => string)) { if(typeof authToken === "string") { this.authTokenString = authToken; } else { this.authTokenFunction = authToken; } } /** * authToken accepts either a string or a function. */ constructor(apiUrl: string, authToken?: string | (() => string), useBearerToken?: boolean) { this.apiUrl = apiUrl; if(authToken !== undefined) { this.setAuthToken(authToken); } if(useBearerToken !== undefined) { this.setUseBearerToken(useBearerToken); } this.agent = request.agent().use(prefix(apiUrl)); /** * !IMPORTANT: DO NOT ADD ERROR HANDLING. API ALWAYS RETURNS RESPONSES AND ERRORS. */ /*.on("error", (err) => { console.log(`Error while making request. Status: ${err.status}, Text: ${err.response?.text}`); throw err; });*/ } public setUseBearerToken(value = true): void { this.useBearerToken = value; } /** * @example * return new ExampleCaller(this.apiUrl, token); */ abstract withToken(token: string): BaseCaller }