UNPKG

@xlink-network/xlink-sdk

Version:
124 lines (106 loc) 2.96 kB
import { backendAPIPrefix } from "../config" import { SDKGlobalContext } from "../xlinkSdkUtils/types.internal" export async function requestAPI<T>( sdkContext: Pick<SDKGlobalContext, "backendAPI">, options: { path: string method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" query?: Record<string, string> body?: Record<string, unknown> }, ): Promise<T> { const queryPairs = Object.entries(options.query ?? {}) const querystring = new URLSearchParams(queryPairs as string[][]).toString() const res = await fetch( `${backendAPIPrefix}${options.path}`.replace(/(\w)\/\//g, "$1/") + (querystring ? "?" + querystring : ""), { method: options.method, headers: { "Content-Type": "application/json", "X-Xlink-Runtime-Env": sdkContext.backendAPI.runtimeEnv, }, body: JSON.stringify(options.body), }, ) return readAPIResponse(res) } export const readAPIResponse = async <T>(resp: Response): Promise<T> => { if (resp.status >= 200 && resp.status < 300) { return resp.json() as any } if (resp.status === 429) { throw new TooManyRequestsError(resp) } const respText = await resp.text() let respData: null | any = null try { respData = JSON.parse(respText) } catch { respData = respText } const thirdPartyError = ThirdPartyRequestError.fromSerializedError(respData) if (thirdPartyError != null) { throw thirdPartyError } throw new RequestError( { url: resp.url, status: resp.status, body: respText, }, { cause: respData, }, ) } export class TooManyRequestsError extends Error { requestUrl: string retryAfter?: number constructor(resp: Response, options?: ErrorConstructorOptions) { const _retryAfter = Number(resp.headers.get("Retry-After")) const retryAfter = Number.isNaN(_retryAfter) ? undefined : _retryAfter let errMsg = `Too many requests to SDK API server` if (retryAfter != null) { errMsg += `; retry after ${retryAfter} seconds` } super(errMsg, { ...options, cause: options?.cause ?? resp, }) this.requestUrl = resp.url this.retryAfter = retryAfter } } export class ThirdPartyRequestError extends Error { isThirdPartyRequestError = true static fromSerializedError(err: any): undefined | ThirdPartyRequestError { if (!err.isThirdPartyRequestError) return return new ThirdPartyRequestError(err.serviceName, { cause: err.cause, }) } constructor( public serviceName: string, options?: ErrorConstructorOptions, ) { super(`Request service ${serviceName} failed`, options) } } export class RequestError extends Error { constructor( public response: { url: string status: number body: string }, options?: ErrorConstructorOptions, ) { super( `Request failed: url: ${response.url} detail: ${response.body}`, options, ) } }