UNPKG

lemon-core

Version:
684 lines 30.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _a, _b; Object.defineProperty(exports, "__esModule", { value: true }); exports.MocksAPIService = exports.createHttpWebProxy = exports.APIService = exports.APIProxyClient = void 0; /** * `api-service.ts` * - common external rest-api service. * - support http-proxy with backbone to overcome VPC restriction. * * * @author Steve Jung <steve@lemoncloud.io> * @date 2019-05-23 initial version * @date 2019-12-03 refactoring for `lemon-core#2.0.0` * * @copyright (C) lemoncloud.io 2019 - All Rights Reserved. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const engine_1 = require("../../engine/"); const shared_1 = require("../../tools/shared"); const test_helper_1 = require("../../common/test-helper"); const fs_1 = __importDefault(require("fs")); const NS = engine_1.$U.NS('APIS', 'green'); // NAMESPACE TO BE PRINTED. /** * class: `APIProxyClient` * - proxed APIServiceClient */ class APIProxyClient { constructor(service) { this.hello = () => this.service.hello(); this.service = service; } doGet(id, cmd, param, body, hash) { return this.service.doGet(id, cmd, param, body, hash); } doPut(id, cmd, param, body, hash) { return this.service.doPut(id, cmd, param, body, hash); } doPost(id, cmd, param, body, hash) { return this.service.doPost(id, cmd, param, body, hash); } doPatch(id, cmd, param, body, hash) { return this.service.doPatch(id, cmd, param, body, hash); } doDelete(id, cmd, param, body, hash) { return this.service.doDelete(id, cmd, param, body, hash); } } exports.APIProxyClient = APIProxyClient; /** * class: `APIService` * - use internal http-proxy service due to restriction internet-face in VPC lambda. */ class APIService { /** * create API service. * * ```js * // basic * const api = new API('web', 'http://localhost:8081', {}); * api.doGet(''); * * // via python * const api = new API('residents', 'http://localhost:8113', {}); * api.doGet('123'); // http GET :8113/residents/123 * * // proxy server * const api = new API('web', 'http://localhost:8081', {}, null, proxy); * api.doGet(''); * ``` * * @param type type in endpoint * @param endpoint base endpoint (support ONLY http, https) * @param headers common headers. * @param client real api-client to use (or use proxy, or create default) * @param proxy proxy-service to use if there is no client (or use backbone server) */ constructor(type, endpoint, headers, client, proxy) { //* relay hello. this.hello = () => `api-service:${this.client.hello()}`; if (!endpoint) throw new Error('@endpoint (url) is required'); if (!endpoint.startsWith('http://') && !endpoint.startsWith('https://')) throw new Error(`@endpoint (url) is not valid http-url:${endpoint}`); this.type = type; this.endpoint = endpoint; this.headers = headers; if (client) { this.client = client; } else if (proxy) { this.client = APIService.buildClient(this.type, this.endpoint, this.headers, null, proxy); } else { //* use default `env.BACKBONE_API` to detect proxy-server. const BACKBONE = engine_1.$engine.environ('BACKBONE_API', 'http://localhost:8081'); this.client = APIService.buildClient(this.type, this.endpoint, this.headers, BACKBONE); } } /** * helper to make http client * * @param backbone backbone address like 'http://localhost:8081' */ static buildClient(type, endpoint, headers, backbone, proxy) { (0, engine_1._log)(NS, `buildClient(${type || ''})...`); if (!endpoint) throw new Error('@endpoint (url) is required'); const host = `${endpoint || ''}`.split('/')[2]; //* if using backbone, need host+path for full-url. or need only `type` + `id/cmd` pair for direct http agent. const base = !proxy && backbone ? `${endpoint || ''}` : undefined; //* make the default proxy-client if not in. if (proxy) { proxy = proxy; } else if (backbone) { //* use web-proxy configuration. const NAME = `WEB:${host}-${type || ''}`; const encoder = (name, path) => encodeURIComponent(path); const relayHeaderKey = 'x-lemon-'; const resultKey = 'result'; //* use default backbone's web-proxy service. proxy = (0, exports.createHttpWebProxy)(NAME, `${backbone}/web`, headers, encoder, relayHeaderKey, resultKey); } else { //* use direct web request.. (only read `type` + `id/cmd` later) const NAME = `API:${host}-${type || ''}`; proxy = (0, exports.createHttpWebProxy)(NAME, endpoint, headers, (n, s) => s, ''); } /** * create internal client to translate of full url path with `host`+`path` */ return new APIService.ProxyServiceClient(proxy, base, type); } /** * make a client for sub-typed endpoint. * @param type sub-type path. */ buildSubTypeClient(type, useRecord, folder) { const client = new APIService.SubTypeClient(this, type); return useRecord ? new APIService.APIServiceClientRecorder(client, `${this.endpoint}/${type}`, folder) : client; } /** * make api recorder of this service. * @param folder base folder (default `./logs`) */ buildRecorder(folder) { return new APIService.APIServiceClientRecorder(this, this.endpoint, folder); } /** * GET HOST/PATH?$param */ doGet(id, cmd, $param, $body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.client.doGet(id, cmd, $param, $body, hash); }); } /** * PUT HOST/PATH?$param */ doPut(id, cmd, $param, $body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.client.doPut(id, cmd, $param, $body, hash); }); } /** * POST HOST/PATH?$param */ doPost(id, cmd, $param, $body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.client.doPost(id, cmd, $param, $body, hash); }); } /** * PATCH HOST/PATH?$param */ doPatch(id, cmd, $param, $body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.client.doPatch(id, cmd, $param, $body, hash); }); } /** * DELETE HOST/PATH?$param */ doDelete(id, cmd, $param, $body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.client.doDelete(id, cmd, $param, $body, hash); }); } } exports.APIService = APIService; /** * class: `TypedEndpoint` * - by using common proxy, extends endpoint by type. * - endpoint := base+'/'+type. */ APIService.ProxyServiceClient = class { constructor(proxy, base, type) { this.asPath = (id, cmd) => { const type = this.type; const _isNa = (a) => a === undefined || a === null; return ('' + (_isNa(type) ? '' : '/' + encodeURIComponent(type)) + (_isNa(type) || _isNa(id) ? '' : '/' + encodeURIComponent(id)) + (_isNa(type) || _isNa(id) || _isNa(cmd) ? '' : '/' + encodeURI(cmd)) + //NOTE - cmd could have additional '/' char. ''); }; this.asPath2 = (id, cmd) => { const _isNa = (a) => a === undefined || a === null; return ('' + (_isNa(id) ? '' : encodeURIComponent(id)) + (_isNa(id) || _isNa(cmd) ? '' : '/' + encodeURI(cmd)) + //NOTE - cmd could have additional '/' char. ''); }; this.asHostPath = (id, cmd) => { let host = this.base ? this.base : this.type; let path = this.base ? this.asPath(id, cmd) : this.asPath2(id, cmd); if (this.base) { const url = (!host.startsWith('http') ? 'http://' : '') + `${host}${path || ''}`; const $url = url_1.default.parse(url); host = `${$url.protocol || 'http'}//${$url.hostname}`; path = `${$url.path}`; // console.info(`! asHostPath(${id}, ${cmd})@1 => `, { host, path }); } else { // console.info(`! asHostPath(${id}, ${cmd})@2 => `, { host, path }); } return { host, path }; }; this.hello = () => `api-client:${this.proxy.hello()}`; this.proxy = proxy; this.base = base; this.type = type; } doGet(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { const { host, path } = this.asHostPath(id, cmd); return this.proxy.doProxy('GET', host, path, param, body, null, hash); }); } doPut(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { const { host, path } = this.asHostPath(id, cmd); return this.proxy.doProxy('PUT', host, path, param, body, null, hash); }); } doPost(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { const { host, path } = this.asHostPath(id, cmd); return this.proxy.doProxy('POST', host, path, param, body, null, hash); }); } doPatch(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { const { host, path } = this.asHostPath(id, cmd); return this.proxy.doProxy('PATCH', host, path, param, body, null, hash); }); } doDelete(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { const { host, path } = this.asHostPath(id, cmd); return this.proxy.doProxy('DELETE', host, path, param, body, null, hash); }); } }; /** * use sub-typed endpoint. * - extends as endpoint := parent.endpoint + '/' + type */ APIService.SubTypeClient = class { constructor(parent, type) { this.hello = () => `sub-typed:${this.parent.hello()}`; this.asCmd = (id, cmd) => { if (id === undefined || id === null) return ''; if (id != encodeURI(id)) throw new Error(`@id (string) is not valid format.`); return cmd !== undefined && cmd !== null ? `${id || ''}/${cmd}` : `${id || ''}`; }; this.parent = parent; this.type = `${type || ''}`; } doGet(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.parent.doGet(this.type, this.asCmd(id, cmd), param, body, hash); }); } doPut(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.parent.doPut(this.type, this.asCmd(id, cmd), param, body, hash); }); } doPost(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.parent.doPost(this.type, this.asCmd(id, cmd), param, body, hash); }); } doPatch(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.parent.doPatch(this.type, this.asCmd(id, cmd), param, body, hash); }); } doDelete(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.parent.doDelete(this.type, this.asCmd(id, cmd), param, body, hash); }); } }; /** * recorder of api-http-proxy client. */ APIService.ApiHttpProxyRecorder = (_a = class { constructor(target, folder) { this.hello = () => `recorder:${this.target.hello()}`; this.target = target; this.folder = `${folder || './logs'}`; } doProxy(method, host, path, param, body, context, hash) { return __awaiter(this, void 0, void 0, function* () { const endpoint = host.startsWith('http://') || host.startsWith('https://') ? `${host}${path}` : `http://${host}${path}`; const index = APIService.ApiHttpProxyRecorder.next++; const load = { method, endpoint, param, body, context }; return this.target .doProxy(method, host, path, param, body, context, hash) .then((data) => ({ index, load, data, error: null })) .catch((error) => ({ index, load, data: null, error })) .then(({ index, load, data, error }) => { const baseDir = (() => { // eslint-disable-next-line prettier/prettier const ts = engine_1.$U.ts().substring(0, '1999-01-01'.length).replace(/\-/ig, ''); const fn = `${this.folder}/R${ts}`; if (index <= 1 && !fs_1.default.existsSync(`${this.folder}`)) fs_1.default.mkdirSync(`${this.folder}`); if (index <= 1 && !fs_1.default.existsSync(fn)) fs_1.default.mkdirSync(fn); return fn; })(); // eslint-disable-next-line prettier/prettier const message = error instanceof Error ? `${error.message}` : typeof error != 'object' ? `${error}` : error ? JSON.stringify(error) : ''; const fn = (n) => { const [S, s] = ['00000', `${n}`]; return n > 0 ? `${S.substring(s.length)}${s}` : s.startsWith('-') ? `N${s.substring(1)}` : s; }; const file = `${baseDir}/P${fn(index)}.json`; fs_1.default.writeFileSync(file, JSON.stringify({ param: load, data, error: message }, null, ' '), 'utf8'); if (error) throw error; else return data; }); }); } }, _a.next = 1, _a); /** * recorder of api-service client. */ APIService.APIServiceClientRecorder = (_b = class { constructor(target, endpoint, folder) { this.hello = () => `recorder:${this.target.hello()}`; this.target = target; this.endpoint = `${endpoint || ''}`; this.folder = `${folder || './logs'}`; } doRecord(method, id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { const index = APIService.APIServiceClientRecorder.next++; const load = { method, endpoint: `${this.endpoint || ''}`, id, cmd, param, body }; const call = (method) => __awaiter(this, void 0, void 0, function* () { if (method == 'GET') return this.target.doGet(id, cmd, param, body, hash); if (method == 'PUT') return this.target.doPut(id, cmd, param, body, hash); if (method == 'POST') return this.target.doPost(id, cmd, param, body, hash); if (method == 'PATCH') return this.target.doPatch(id, cmd, param, body, hash); if (method == 'DELETE') return this.target.doDelete(id, cmd, param, body, hash); throw new Error(`@method is not valid. method:${method}`); }); return call(method) .then((data) => ({ index, load, data, error: null })) .catch((error) => ({ index, load, data: null, error })) .then(({ index, load, data, error }) => { const baseDir = (() => { // eslint-disable-next-line prettier/prettier const ts = engine_1.$U.ts().substring(0, '1999-01-01'.length).replace(/\-/ig, ''); const fn = `${this.folder}/R${ts}`; if (index <= 1 && !fs_1.default.existsSync(`${this.folder}`)) fs_1.default.mkdirSync(`${this.folder}`); if (index <= 1 && !fs_1.default.existsSync(fn)) fs_1.default.mkdirSync(fn); return fn; })(); // eslint-disable-next-line prettier/prettier const message = error instanceof Error ? `${error.message}` : typeof error != 'object' ? `${error}` : error ? JSON.stringify(error) : ''; const fn = (n) => { const [S, s] = ['00000', `${n}`]; return n > 0 ? `${S.substring(s.length)}${s}` : s.startsWith('-') ? `N${s.substring(1)}` : s; }; const file = `${baseDir}/D${fn(index)}.json`; fs_1.default.writeFileSync(file, JSON.stringify({ param: load, data, error: message }, null, ' '), 'utf8'); if (error) throw error; else return data; }); }); } doGet(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.doRecord('GET', id, cmd, param, body, hash); }); } doPut(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.doRecord('PUT', id, cmd, param, body, hash); }); } doPost(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.doRecord('POST', id, cmd, param, body, hash); }); } doPatch(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.doRecord('PATCH', id, cmd, param, body, hash); }); } doDelete(id, cmd, param, body, hash) { return __awaiter(this, void 0, void 0, function* () { return this.doRecord('DELETE', id, cmd, param, body, hash); }); } }, _b.next = 1, _b); /** ******************************************************************************************************************** * BODY IMPLEMENTATION. ** ********************************************************************************************************************/ const url_1 = __importDefault(require("url")); const request_1 = __importDefault(require("request")); const query_string_1 = __importDefault(require("query-string")); /** * create http-web-proxy agent which using endpoint as proxy server. * * # as cases. * as proxy agent: GET <endpoint>/<host?>/<path?> * as direct agent: GET <endpoint>/<id?>/<cmd?> * * @param name client-name * @param endpoint service url (or backbone proxy-url) * @param headers headers * @param encoder path encoder (default encodeURIComponent) * @param relayHeaderKey relay-key in headers for proxy. * @param resultKey resultKey in response */ const createHttpWebProxy = (name, endpoint, headers, encoder, relayHeaderKey, resultKey) => { if (!endpoint) throw new Error('@endpoint (url) is required!'); const NS = engine_1.$U.NS(`X${name}`, 'magenta'); // NAMESPACE TO BE PRINTED. encoder = encoder !== undefined ? encoder : (name, path) => path; relayHeaderKey = relayHeaderKey || ''; /** * class: `ApiHttpProxy` * - http proxy client via backbone's web. */ return new (class { constructor() { this.hello = () => `http-web-proxy:${name}`; } doProxy(method, path1, path2, $param, $body, ctx) { // const _log = console.info; if (!method) throw new Error('@method is required!'); (0, engine_1._log)(NS, `doProxy(${method})..`); const _isNa = (a) => a === undefined || a === null; (0, engine_1._log)(NS, '> endpoint =', endpoint); _isNa(path1) && (0, engine_1._log)(NS, `> host(id) =`, typeof path1, path1); _isNa(path2) && (0, engine_1._log)(NS, `> path(cmd) =`, typeof path2, path2); //* prepare request parameters // eslint-disable-next-line prettier/prettier const query_string = _isNa($param) ? '' : (typeof $param == 'object' ? query_string_1.default.stringify($param) : `${$param}`); const url = endpoint + (_isNa(path1) ? '' : `/${encoder('host', path1)}`) + (_isNa(path1) && _isNa(path2) ? '' : `/${encoder('path', path2)}`) + (!query_string ? '' : '?' + query_string); const request = request_1.default; const options = { method, uri: url, headers: {}, body: $body === null ? undefined : $body, json: typeof $body === 'string' ? false : true, }; //* relay HEADERS to `WEB-API` if (headers) { options.headers = Object.keys(headers).reduce((H, key) => { const val = headers[key]; const name = `${relayHeaderKey}${key}`; const text = `${val}`; H[name] = text; return H; }, options.headers); } (0, engine_1._log)(NS, ' url :=', options.method, url); (0, engine_1._log)(NS, '*', options.method, url, options.json ? 'json' : 'plain'); (0, engine_1._log)(NS, '> options =', engine_1.$U.json(options)); //* returns promise return new Promise((resolve, reject) => { //* start request.. request(options, function (error, response, body) { error && (0, engine_1._err)(NS, '>>>>> requested! err=', error); if (error) return reject(error instanceof Error ? error : new Error((0, test_helper_1.GETERR)(error))); //* detecte trouble. const statusCode = response.statusCode; const statusMessage = response.statusMessage; //* if not in success if (statusCode !== 200 && statusCode !== 201) { const msg = body ? (0, test_helper_1.GETERR)(body) : `${statusMessage || ''}`; if (statusCode === 400 || statusCode === 404) { const title = `${(statusCode == 404 ? '' : statusMessage) || 'NOT FOUND'}`.toUpperCase(); const message = msg.startsWith('404 NOT FOUND') ? msg : `${statusCode} ${title} - ${msg}`; return reject(new Error(message)); } statusMessage && (0, engine_1._log)(NS, `> statusMessage[${statusCode}] =`, statusMessage); body && (0, engine_1._log)(NS, `> body[${statusCode}] =`, engine_1.$U.json(body)); return reject(new Error(`${statusCode} ${statusMessage || 'FAILURE'} - ${msg}`)); } //* try to parse body. try { if (body && typeof body == 'string' && body.startsWith('{') && body.endsWith('}')) { body = JSON.parse(body); } else if (body && typeof body == 'string' && body.startsWith('[') && body.endsWith(']')) { body = JSON.parse(body); } } catch (e) { (0, engine_1._err)(NS, '!WARN! parse(body) =', e instanceof Error ? e : engine_1.$U.json(e)); } //* ok! successed. resolve(body); }); }).then((res) => { if (resultKey && res && res[resultKey] !== undefined) return res[resultKey]; return res; }); } })(); }; exports.createHttpWebProxy = createHttpWebProxy; /** ******************************************************************************************************************** * MOCKS API-SERVICE ** ********************************************************************************************************************/ /** * class: `MocksAPIService` * - use <mock>.json file in `./data/mocks/` instead of real http request. * - it redirect to url like `endpoint/type/id/cmd` * * ```ts * // json format * { * param: { // input format * method: string; * endpoint: string; * id?: string; * cmd?: string; * }, * data: { // response data * ... * }, * error?: string; // in case of error. * } * ``` */ class MocksAPIService { constructor(type, endpoint) { this.asPath = (id, cmd) => { const _isNa = (a) => a === undefined || a === null; return (_isNa(id) ? '' : encodeURIComponent(id)) + (_isNa(id) || !cmd ? '' : '/' + encodeURI(cmd)); }; this.na = (a, x, y) => (a === undefined || a === null ? x : y); this.hello = () => `mocks-api-service:${this.endpoint}${this.na(this.type, '', '/')}${this.type || ''}`; this.type = type; this.endpoint = endpoint; } loadSync() { if (this.$map) return; const PATH = './data/mocks/'; const files = fs_1.default.readdirSync(PATH); // console.log(NS, '> files =', files); const $map = files .sort() .map(file => ({ file, json: (0, shared_1.loadJsonSync)(`${PATH}${file}`) })) .reduce((M, F) => { const file = F.file || ''; const data = F.json; const param = data.param || {}; const { method, endpoint: endpoint0, id, cmd, param: $qs } = param; const has = (a) => a !== undefined && a !== null; const [endpoint, hash] = `${endpoint0}`.split('#', 2); const qs = $qs ? engine_1.$U.qs.stringify($qs) : ''; const url = `${endpoint}` + (has(id) ? `/${id}` : '') + (has(id) && has(cmd) ? `/${cmd}` : ''); const key = `${method} ${url}`; const key2 = qs ? `${key}${key.indexOf('?') > 0 ? '&' : '?'}${qs}` : key; const key3 = hash ? `${key2}${hash ? '#' : ''}${hash || ''}` : key2; // if (file.indexOf('#') > 0) console.info(`! file[${file}] =`, key3); //* save by file & key. M[file] = data; M[key3] = data; return M; }, {}); // console.log(NS, '> $map =', $map); this.$map = $map; } doProxy(method, type, path, param, body, ctx, hash) { return __awaiter(this, void 0, void 0, function* () { // console.info(`! mocks.proxy(${method},${type},${path})...`); this.loadSync(); const file = path && path.endsWith('.json') ? path.split('/').pop() : ''; // eslint-disable-next-line prettier/prettier const key = `${method} ${this.endpoint}${this.na(type, '', '/')}${type || ''}${!path || path.startsWith('/') ? '' : '/'}${path || ''}`; const qs = param ? engine_1.$U.qs.stringify(param) : ''; const key2 = qs ? `${key}${path.indexOf('?') > 0 ? '&' : '?'}${qs}` : key; const key3 = hash ? `${key2}${hash.startsWith('#') ? '' : '#'}${hash}` : key2; // if (param) console.info('!key[] =', [key3, key2, key]); // if (hash) console.info(`! hash[${hash}].keys =`, [key3, key2, key]); const data = this.$map[file] || this.$map[key3] || this.$map[key2] || this.$map[key]; if (!data) throw new Error(`404 NOT FOUND - ${key3}`); const err = data.error; if (err && typeof err == 'string') { if (err.startsWith('{') && err.endsWith('}')) throw JSON.parse(err); else throw new Error(err); } else if (err) { throw err; } //* returns data. return data.data ? JSON.parse(engine_1.$U.json(data.data)) : data.data; }); } doGet(id, cmd, param, body, hash) { const path = this.asPath(id, cmd); // use mocks.type infor return this.doProxy('GET', this.type, path, param, body, null, hash); } doPut(id, cmd, param, body, hash) { const path = this.asPath(id, cmd); // use mocks.type infor return this.doProxy('PUT', this.type, path, param, body, null, hash); } doPost(id, cmd, param, body, hash) { const path = this.asPath(id, cmd); // use mocks.type infor return this.doProxy('POST', this.type, path, param, body, null, hash); } doPatch(id, cmd, param, body, hash) { const path = this.asPath(id, cmd); // use mocks.type infor return this.doProxy('PATCH', this.type, path, param, body, null, hash); } doDelete(id, cmd, param, body, hash) { const path = this.asPath(id, cmd); // use mocks.type infor return this.doProxy('DELETE', this.type, path, param, body, null, hash); } } exports.MocksAPIService = MocksAPIService; //# sourceMappingURL=api-service.js.map