/** * Implemented by client */ export public interface ~ApiExecuterI { public async exec( method: string, path: string, pathParams: ~Object+, queryParams: ~Object+, headerParams: ~Object+, payloadContentType: string, body: any+) : Promise>; } export public interface ~ApiError { public resultBody?: T; } export public function checkRequiredParams(apiName: string, params: ~Object+) : void { for (const key of Object.keys(params)) { const arg = params[key]; if (arg == null) { throw new Error('Required parameter ' + key + ' was null or undefined when calling ' + apiName + '.'); } } } export public function cleanCopyBody(t : T+, ...properties: string) : ~T { const copy : ~T+ = {}; for (const prop in properties) { copy[prop] = t.prop; } return copy; } /** * Default implementation of ApiExecuterI * * The following dependencies are necessary: * - n4js-runtime-esnext * - n4js-runtime-es2015 * - n4js-runtime-html5 */ export public class FetchApiExec implements ApiExecuterI { public apiOrigin: string; const jsonTypes = ["application/json", "application/problem+json"]; @Override public async exec( method: string, path: string, pathParams: ~Object+, queryParams: ~Object+, headerParams: ~Object+, payloadContentType: string, body: any+ ): Promise> { if (pathParams) { for (const [k, v] of Object.entries(pathParams)) { path = path.replace(`{${k}}`, encodeURIComponent(String(v))); } } const query: string[] = []; if (queryParams) { for (const [k, v] of Object.entries(queryParams)) { query.push(`${k}=${encodeURIComponent(String(v))}`); } } let url = `${this.apiOrigin}${path}`; if (query.length) { url += `?${query.join("&")}`; } const headers: Object+ = {}; if (payloadContentType) { headers["content-type"] = payloadContentType; if (this.constructor.jsonTypes.includes(payloadContentType)) { body = JSON.stringify(body); } } Object.assign(headers, headerParams); return await this.fetchExec(url, { method, headers, body, }); } protected async fetchExec(url: string, reqInit: RequestInit): Promise> { const resp = await fetch(url, reqInit); if (resp.status !== 204) { const contentType = (resp.headers.get("content-type") || "").split(";")[0]; const body = this.constructor.jsonTypes.includes(contentType) ? await resp.json() : await resp.text(); if (!resp.ok) { await this.handleError(resp, body); } return body as R; } return null; } protected async handleError(resp: Response, body): Promise> { throw {body: body}; } }