UNPKG

cryptomarket

Version:

The CryptoMarket for Node.js

125 lines (106 loc) 3.8 kB
import fetch from "node-fetch"; import { URL, URLSearchParams } from "url"; import { CryptomarketAPIException, CryptomarketSDKException, } from "./exceptions"; import { HMAC } from "./hmac"; import { HTTP_METHOD } from "./httpMethods"; export class HttpClient { apiPath: string hmac: HMAC constructor(apiUrl: string, apiVersion: string, apiKey: string, apiSecret: string, window: number | null = null) { this.apiPath = apiUrl + `/api/${apiVersion}/` this.hmac = new HMAC(apiKey, apiSecret, window) } changeWindow(window: number) { this.hmac.changeWindow(window) } changeCredentials(apiKey: string, apiSecret: string) { this.hmac.changeCredentials(apiKey, apiSecret) } async makeRequest( method: HTTP_METHOD, endpoint: string, params: any, publc: boolean = false ): Promise<any> { const { url, opts } = this.prepareRequest(params, method, publc, endpoint); try { return await this.makeFetch(url, opts); } catch (e) { throw new CryptomarketSDKException("Failed request to server. " + e, e); } } private prepareRequest(paramsRaw: any, method: HTTP_METHOD, publicMethod: boolean, endpoint: string): { url: URL, opts: Map<string, string> } { if (paramsRaw === undefined || paramsRaw === null) { paramsRaw = {} } let url = new URL(this.apiPath + endpoint); this.removeNulls(paramsRaw); const params: [string, string][] = Object.entries(paramsRaw) .map(([k, v]) => [k, String(v)]) let rawQuery = new URLSearchParams(params); rawQuery.sort(); let query = rawQuery.toString(); // build fetch options let opts: any = { method: method, headers: { "User-Agent": "cryptomarket/node", } }; let credentialParams = query if (method === HTTP_METHOD.POST) { opts.headers["Content-Type"] = "application/json"; credentialParams = JSON.stringify(paramsRaw) } if (method === HTTP_METHOD.PATCH) { opts.headers["Content-Type"] = "application/x-www-form-urlencoded"; } // add auth header if not public endpoint if (!publicMethod) opts.headers["Authorization"] = this.hmac.buildCredential(method, url, credentialParams); // include query params to call if (method === HTTP_METHOD.GET || method === HTTP_METHOD.PUT) url.search = query; else { opts.body = credentialParams; } return { url, opts }; } private removeNulls(paramsRaw: any) { Object.keys(paramsRaw).forEach(key => (paramsRaw[key] === undefined || paramsRaw[key] == null) ? delete paramsRaw[key] : {}); } private async makeFetch(url: URL, opts: any): Promise<any> { const response = await fetch(url, opts) let jsonResponse: any try { jsonResponse = await response.json() } catch (e) { throw new CryptomarketSDKException(`Failed to parse response: ${response}`, e) } if (!response.ok) { throw new CryptomarketAPIException(jsonResponse["error"], response.status) } return jsonResponse } async publicGet(endpoint: string, params: any) { return this.makeRequest(HTTP_METHOD.GET, endpoint, params, true); } async get(endpoint: string, params: any | null = null) { return this.makeRequest(HTTP_METHOD.GET, endpoint, params); } async patch(endpoint: string, params: any) { return this.makeRequest(HTTP_METHOD.PATCH, endpoint, params); } async post(endpoint: string, params: any) { return this.makeRequest(HTTP_METHOD.POST, endpoint, params); } async delete(endpoint: string, params: any | null = null) { return this.makeRequest(HTTP_METHOD.DELETE, endpoint, params); } async put(endpoint: string, params: any | null = null) { return this.makeRequest(HTTP_METHOD.PUT, endpoint, params); } }