UNPKG

jswagger-client

Version:

This is jswagger's client package.

335 lines (334 loc) 17.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const axios_1 = __importDefault(require("axios")); const node_json_bigint_1 = __importDefault(require("node-json-bigint")); const url = __importStar(require("url")); const types_1 = require("./types"); const jswagger_common_1 = require("jswagger-common"); const internals_1 = require("./internals"); function extractRef(ref) { const refMatcher = /#\/(\w+)\/(.*)/.exec(ref); if (!refMatcher) { return null; } return { type: refMatcher[1], name: refMatcher[2] }; } const REGEX_CONTENT_TYPE_APPLICATION_JSON = /application\/json(?:\s*;\s*charset=([a-zA-Z0-9_-]+))?/; const REGEX_CONTENT_TYPE_TEXT = /text\/([^;]+)(?:\s*;\s*charset=([a-zA-Z0-9_-]+))?/; function toBufferEncoding(input) { return (input && input.toUpperCase().startsWith('ISO-8859') && 'ascii') || input || 'utf8'; } function basicTransformResponse(data, headers) { const jsonCheck = headers['content-type'] && REGEX_CONTENT_TYPE_APPLICATION_JSON.exec(headers['content-type']); const textCheck = jsonCheck ? null : headers['content-type'] && REGEX_CONTENT_TYPE_TEXT.exec(headers['content-type']); const dataBuffer = (Buffer.isBuffer(data) ? data : internals_1.arrayBufferToBuffer(data)); const encoding = toBufferEncoding(jsonCheck ? jsonCheck[1] : textCheck ? textCheck[2] : undefined); if (jsonCheck) { const text = dataBuffer.toString(encoding); return node_json_bigint_1.default.parse(text); } else if (textCheck) { return dataBuffer.toString(encoding); } return dataBuffer; } function urlConcat(a, b) { if (a.length && b.length) { const ta = a.charAt(a.length - 1) === '/'; const tb = b.charAt(0) === '/'; if (ta === tb) { if (ta) { return a.concat(b.substring(1)); } else { return a.concat('/', b); } } } return a.concat(b); } function concatHandlers(first, others) { if (others && others) { if (Array.isArray(others)) { return [first].concat(others); } else { return [first, others]; } } else { return [first]; } } function safePromiseCallback(runner) { try { return runner(); } catch (e) { return Promise.reject(e); } } const CONTENT_TYPE_TESTERS = [ (data) => Buffer.isBuffer(data) ? 'application/octet-stream' : null, (data) => (typeof data === 'object') ? 'application/json;charset=utf-8' : null, (data) => (typeof data === 'string') ? 'text/plain' : null ]; class SwaggerClient { constructor(config) { this._config = config; if (config.baseUrl) { this._baseUrl = config.baseUrl; } else { this._baseUrl = url.format({ protocol: config.protocol || config.spec.protocol || 'http', host: config.host || config.spec.host, pathname: config.spec.basePath }); } } static urlConcat(a, b) { return urlConcat(a, b); } _defaultContentTypeResolve(params, data) { const r = CONTENT_TYPE_TESTERS.reduce((prev, cur) => { if (prev) { return prev; } else { return cur(data); } }, null); return r || 'text/plain'; } api(api, options) { const _options = options || {}; const self = this; const apis = jswagger_common_1.findApisByTag(this._config.spec, api.tag); const proxy = {}; const definitionClasses = api.specMetadata.classes.reduce((results, clazz) => { const definitionName = api.specMetadata.getSwaggerDefinitionName(clazz); results.set(definitionName, clazz); return results; }, new Map()); apis.forEach(item => { let apiPath = item.path; Object.defineProperty(proxy, item.api.operationId, { get: () => function () { let callOptions = arguments[0]; let retryCount = 0; const retryParams = { operationId: item.api.operationId, arg: callOptions }; return (self._config.contentTypeResolver && self._config.contentTypeResolver(retryParams, callOptions && callOptions.data) || Promise.resolve(null)).then(contentType => contentType || self._defaultContentTypeResolve(retryParams, callOptions && callOptions.data)).then(contentType => { const doExecute = () => { if (self._config.argRewriter) { const replaced = self._config.argRewriter({ operationId: item.api.operationId, arg: callOptions && Object.assign({}, callOptions) }); callOptions = replaced || callOptions; } const apiRequestOptions = callOptions && callOptions; const securityContext = _options['securityContext'] || self._config.securityContext; const optBody = callOptions && callOptions['data']; const optParams = callOptions && callOptions['params']; const reqBody = optBody; const baseUrl = apiRequestOptions && apiRequestOptions.baseURL || self._baseUrl; const rewriterParams = { operationId: item.api.operationId, arg: callOptions }; let reqHeaders = { 'content-type': contentType }; let reqQueries = {}; if (optParams) { item.api.parameters.forEach(parameterInfo => { if (parameterInfo.in === 'header') { const foundItem = Object.entries(optParams).find(([key, value]) => key === parameterInfo.name); if (foundItem) { reqHeaders[parameterInfo.name] = foundItem[1]; } } else if (parameterInfo.in === 'query') { const foundItem = Object.entries(optParams).find(([key, value]) => key === parameterInfo.name); if (foundItem) { reqQueries[parameterInfo.name] = foundItem[1]; } } else if (parameterInfo.in === 'path') { const foundItem = Object.entries(optParams).find(([key, value]) => key === parameterInfo.name); if (foundItem) { apiPath = apiPath.replace(`{${parameterInfo.name}}`, foundItem[1]); } } }); } let apiUrl = new url.URL(urlConcat(baseUrl, apiPath)); if (apiRequestOptions && apiRequestOptions.protocol) { apiUrl.protocol = apiRequestOptions.protocol; } if (apiRequestOptions && apiRequestOptions.host) { apiUrl.host = apiRequestOptions.host; } if (self._config.hostRewriter) { const result = self._config.hostRewriter(rewriterParams); if (result) { apiUrl.protocol = result.protocol || apiUrl.protocol; apiUrl.host = result.host || apiUrl.host; } } if (self._config.urlRewriter) { const result = self._config.urlRewriter(rewriterParams, apiUrl); apiUrl = result || apiUrl; } let searchParams = []; Object.keys(reqQueries) .forEach(k => { searchParams.push({ name: k, value: reqQueries[k] }); }); if (apiRequestOptions && apiRequestOptions.queries) { searchParams.push(...apiRequestOptions.queries); } if (securityContext) { if (securityContext.headerReplacer) { reqHeaders = securityContext.headerReplacer(reqHeaders); } if (securityContext.queryReplacer) { searchParams = securityContext.queryReplacer(searchParams); } } if (apiRequestOptions && apiRequestOptions.headers) { Object.assign(reqHeaders, apiRequestOptions.headers); } searchParams.forEach(item => { apiUrl.searchParams.append(item.name, item.value); }); const axioxRequestConfig = Object.assign({}, apiRequestOptions || {}); if (axioxRequestConfig['securityContext']) delete axioxRequestConfig['securityContext']; if (axioxRequestConfig['params']) delete axioxRequestConfig['params']; if (axioxRequestConfig['queries']) delete axioxRequestConfig['queries']; if (axioxRequestConfig['data']) delete axioxRequestConfig['data']; if (axioxRequestConfig['baseURL']) delete axioxRequestConfig['baseURL']; Object.assign(axioxRequestConfig, { responseType: 'arraybuffer', headers: reqHeaders, httpAgent: self._config.httpAgent, httpsAgent: self._config.httpsAgent, transformResponse: concatHandlers(basicTransformResponse, apiRequestOptions && apiRequestOptions.transformResponse) }); return ((() => { if (['get', 'delete', 'head', 'options'].includes(item.method)) { return axios_1.default[item.method](apiUrl.toString(), axioxRequestConfig); } else { return axios_1.default[item.method](apiUrl.toString(), reqBody, axioxRequestConfig); } })()) .then(res => { const responseDefinition = item.api.responses && item.api.responses[res.status.toString()]; const responseRef = responseDefinition && responseDefinition.schema && extractRef(responseDefinition.schema.$ref); const responseClazz = responseRef && definitionClasses.get(responseRef.name); const out = Object.assign({}, res); if (responseClazz) { out.data = new responseClazz({ schema: res.data }); } else if (responseDefinition && responseDefinition.schema) { out.data = internals_1.leafConvertToClassValue(responseDefinition.schema, res.data); } return out; }) .catch((err) => { if (err.response) { const responseDefinition = item.api.responses && item.api.responses[err.response.status.toString()]; const responseRef = responseDefinition && responseDefinition.schema && responseDefinition.schema.$ref; const responseDefinitionClass = (() => { const refMatcher = extractRef(responseRef); if (!refMatcher) { return undefined; } return api.specMetadata.classes .find(v => api.specMetadata.getSwaggerDefinitionName(v) === refMatcher.name); })(); const responseVO = responseDefinitionClass ? new responseDefinitionClass({ schema: err.response.data }) : err.response.data; return Promise.reject(new types_1.ApiError({ message: responseDefinition ? responseDefinition.description || err.message : err.message, code: err.code || 'ApiError', status: err.response.status, data: responseVO, headers: err.response.headers, axiosError: err, axiosConfig: err.config, axiosRequest: err.request, axiosResponse: err.response })); } else { return Promise.reject(err); } }); }; const doExecuteWithRetry = (resolve, reject) => { doExecute() .then(resolve) .catch(e => { if (self._config.retryHandler) { safePromiseCallback(self._config.retryHandler.bind(null, retryParams, retryCount++, e)) .then(delay => { if (delay < 0 || delay === false) { reject(e); } else if (delay === 0) { doExecuteWithRetry(resolve, reject); } else { setTimeout(() => doExecuteWithRetry(resolve, reject), delay); } }) .catch(reject); } else { reject(e); } }); }; return new Promise((resolve, reject) => { doExecuteWithRetry(resolve, reject); }); }); } }); }); return proxy; } } exports.default = SwaggerClient;