source: node_modules/swagger-client/lib/execute/index.js

main
Last change on this file was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 13.2 KB
Line 
1"use strict";
2
3var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard").default;
4var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
5exports.__esModule = true;
6exports.baseUrl = baseUrl;
7exports.buildRequest = buildRequest;
8exports.execute = execute;
9exports.self = void 0;
10var _cookie = _interopRequireDefault(require("cookie"));
11var _isPlainObject = require("is-plain-object");
12var _empty = require("@swagger-api/apidom-reference/configuration/empty");
13var _constants = require("../constants.js");
14var _index = _interopRequireWildcard(require("../http/index.js"));
15var _createError = _interopRequireDefault(require("../specmap/lib/create-error.js"));
16var _parameterBuilders = _interopRequireDefault(require("./swagger2/parameter-builders.js"));
17var OAS3_PARAMETER_BUILDERS = _interopRequireWildcard(require("./oas3/parameter-builders.js"));
18var _buildRequest = _interopRequireDefault(require("./oas3/build-request.js"));
19var _buildRequest2 = _interopRequireDefault(require("./swagger2/build-request.js"));
20var _index2 = require("../helpers/index.js");
21var _openapiPredicates = require("../helpers/openapi-predicates.js");
22const arrayOrEmpty = ar => Array.isArray(ar) ? ar : [];
23
24/**
25 * `parseURIReference` function simulates the behavior of `node:url` parse function.
26 * New WHATWG URL API is not capable of parsing relative references natively,
27 * but can be adapter by utilizing the `base` parameter.
28 */
29const parseURIReference = uriReference => {
30 try {
31 return new URL(uriReference);
32 } catch {
33 const parsedURL = new URL(uriReference, _constants.DEFAULT_BASE_URL);
34 const pathname = String(uriReference).startsWith('/') ? parsedURL.pathname : parsedURL.pathname.substring(1);
35 return {
36 hash: parsedURL.hash,
37 host: '',
38 hostname: '',
39 href: '',
40 origin: '',
41 password: '',
42 pathname,
43 port: '',
44 protocol: '',
45 search: parsedURL.search,
46 searchParams: parsedURL.searchParams
47 };
48 }
49};
50const OperationNotFoundError = (0, _createError.default)('OperationNotFoundError', function cb(message, extra, oriError) {
51 this.originalError = oriError;
52 Object.assign(this, extra || {});
53});
54const findParametersWithName = (name, parameters) => parameters.filter(p => p.name === name);
55
56// removes parameters that have duplicate 'in' and 'name' properties
57const deduplicateParameters = parameters => {
58 const paramsMap = {};
59 parameters.forEach(p => {
60 if (!paramsMap[p.in]) {
61 paramsMap[p.in] = {};
62 }
63 paramsMap[p.in][p.name] = p;
64 });
65 const dedupedParameters = [];
66 Object.keys(paramsMap).forEach(i => {
67 Object.keys(paramsMap[i]).forEach(p => {
68 dedupedParameters.push(paramsMap[i][p]);
69 });
70 });
71 return dedupedParameters;
72};
73
74// For stubbing in tests
75const self = exports.self = {
76 buildRequest
77};
78
79// Execute request, with the given operationId and parameters
80// pathName/method or operationId is optional
81function execute({
82 http: userHttp,
83 fetch,
84 // This is legacy
85 spec,
86 operationId,
87 pathName,
88 method,
89 parameters,
90 securities,
91 ...extras
92}) {
93 // Provide default fetch implementation
94 const http = userHttp || fetch || _index.default; // Default to _our_ http
95
96 if (pathName && method && !operationId) {
97 operationId = (0, _index2.idFromPathMethodLegacy)(pathName, method);
98 }
99 const request = self.buildRequest({
100 spec,
101 operationId,
102 parameters,
103 securities,
104 http,
105 ...extras
106 });
107 if (request.body && ((0, _isPlainObject.isPlainObject)(request.body) || Array.isArray(request.body))) {
108 request.body = JSON.stringify(request.body);
109 }
110
111 // Build request and execute it
112 return http(request);
113}
114
115// Build a request, which can be handled by the `http.js` implementation.
116function buildRequest(options) {
117 const {
118 spec,
119 operationId,
120 responseContentType,
121 scheme,
122 requestInterceptor,
123 responseInterceptor,
124 contextUrl,
125 userFetch,
126 server,
127 serverVariables,
128 http,
129 signal
130 } = options;
131 let {
132 parameters,
133 parameterBuilders
134 } = options;
135 const specIsOAS3 = (0, _openapiPredicates.isOpenAPI3)(spec);
136 if (!parameterBuilders) {
137 // user did not provide custom parameter builders
138 if (specIsOAS3) {
139 parameterBuilders = OAS3_PARAMETER_BUILDERS;
140 } else {
141 parameterBuilders = _parameterBuilders.default;
142 }
143 }
144
145 // Set credentials with 'http.withCredentials' value
146 const credentials = http && http.withCredentials ? 'include' : 'same-origin';
147
148 // Base Template
149 let req = {
150 url: '',
151 credentials,
152 headers: {},
153 cookies: {}
154 };
155 if (signal) {
156 req.signal = signal;
157 }
158 if (requestInterceptor) {
159 req.requestInterceptor = requestInterceptor;
160 }
161 if (responseInterceptor) {
162 req.responseInterceptor = responseInterceptor;
163 }
164 if (userFetch) {
165 req.userFetch = userFetch;
166 }
167 const operationRaw = (0, _index2.getOperationRaw)(spec, operationId);
168 if (!operationRaw) {
169 throw new OperationNotFoundError(`Operation ${operationId} not found`);
170 }
171 const {
172 operation = {},
173 method,
174 pathName
175 } = operationRaw;
176 req.url += baseUrl({
177 spec,
178 scheme,
179 contextUrl,
180 server,
181 serverVariables,
182 pathName,
183 method
184 });
185
186 // Mostly for testing
187 if (!operationId) {
188 // Not removing req.cookies causes testing issues and would
189 // change our interface, so we're always sure to remove it.
190 // See the same statement lower down in this function for
191 // more context.
192 delete req.cookies;
193 return req;
194 }
195 req.url += pathName; // Have not yet replaced the path parameters
196 req.method = `${method}`.toUpperCase();
197 parameters = parameters || {};
198 const path = spec.paths[pathName] || {};
199 if (responseContentType) {
200 req.headers.accept = responseContentType;
201 }
202 const combinedParameters = deduplicateParameters([].concat(arrayOrEmpty(operation.parameters)) // operation parameters
203 .concat(arrayOrEmpty(path.parameters))); // path parameters
204
205 // REVIEW: OAS3: have any key names or parameter shapes changed?
206 // Any new features that need to be plugged in here?
207
208 // Add values to request
209 combinedParameters.forEach(parameter => {
210 const builder = parameterBuilders[parameter.in];
211 let value;
212 if (parameter.in === 'body' && parameter.schema && parameter.schema.properties) {
213 value = parameters;
214 }
215 value = parameter && parameter.name && parameters[parameter.name];
216 if (typeof value === 'undefined') {
217 // check for `name-in` formatted key
218 value = parameter && parameter.name && parameters[`${parameter.in}.${parameter.name}`];
219 } else if (findParametersWithName(parameter.name, combinedParameters).length > 1) {
220 // value came from `parameters[parameter.name]`
221 // check to see if this is an ambiguous parameter
222 // eslint-disable-next-line no-console
223 console.warn(`Parameter '${parameter.name}' is ambiguous because the defined spec has more than one parameter with the name: '${parameter.name}' and the passed-in parameter values did not define an 'in' value.`);
224 }
225 if (value === null) {
226 return;
227 }
228 if (typeof parameter.default !== 'undefined' && typeof value === 'undefined') {
229 value = parameter.default;
230 }
231 if (typeof value === 'undefined' && parameter.required && !parameter.allowEmptyValue) {
232 throw new Error(`Required parameter ${parameter.name} is not provided`);
233 }
234 if (specIsOAS3 && parameter.schema && parameter.schema.type === 'object' && typeof value === 'string') {
235 try {
236 value = JSON.parse(value);
237 } catch (e) {
238 throw new Error('Could not parse object parameter value string as JSON');
239 }
240 }
241 if (builder) {
242 builder({
243 req,
244 parameter,
245 value,
246 operation,
247 spec
248 });
249 }
250 });
251
252 // Do version-specific tasks, then return those results.
253 const versionSpecificOptions = {
254 ...options,
255 operation
256 };
257 if (specIsOAS3) {
258 req = (0, _buildRequest.default)(versionSpecificOptions, req);
259 } else {
260 // If not OAS3, then treat as Swagger2.
261 req = (0, _buildRequest2.default)(versionSpecificOptions, req);
262 }
263
264 // If the cookie convenience object exists in our request,
265 // serialize its content and then delete the cookie object.
266 if (req.cookies && Object.keys(req.cookies).length) {
267 const cookieString = Object.keys(req.cookies).reduce((prev, cookieName) => {
268 const cookieValue = req.cookies[cookieName];
269 const prefix = prev ? '&' : '';
270 const stringified = _cookie.default.serialize(cookieName, cookieValue);
271 return prev + prefix + stringified;
272 }, '');
273 req.headers.Cookie = cookieString;
274 }
275 if (req.cookies) {
276 // even if no cookies were defined, we need to remove
277 // the cookies key from our request, or many legacy
278 // tests will break.
279 delete req.cookies;
280 }
281
282 // Will add the query object into the URL, if it exists
283 // ... will also create a FormData instance, if multipart/form-data (eg: a file)
284 (0, _index.mergeInQueryOrForm)(req);
285 return req;
286}
287const stripNonAlpha = str => str ? str.replace(/\W/g, '') : null;
288
289// be careful when modifying this! it is a publicly-exposed method.
290function baseUrl(obj) {
291 const specIsOAS3 = (0, _openapiPredicates.isOpenAPI3)(obj.spec);
292 return specIsOAS3 ? oas3BaseUrl(obj) : swagger2BaseUrl(obj);
293}
294const isNonEmptyServerList = value => Array.isArray(value) && value.length > 0;
295function oas3BaseUrl({
296 spec,
297 pathName,
298 method,
299 server,
300 contextUrl,
301 serverVariables = {}
302}) {
303 var _spec$paths, _spec$paths2;
304 let servers = [];
305 let selectedServerUrl = '';
306 let selectedServerObj;
307
308 // compute the servers (this will be taken care of by ApiDOM refrator plugins in future
309 const operationLevelServers = spec == null || (_spec$paths = spec.paths) == null || (_spec$paths = _spec$paths[pathName]) == null || (_spec$paths = _spec$paths[(method || '').toLowerCase()]) == null ? void 0 : _spec$paths.servers;
310 const pathItemLevelServers = spec == null || (_spec$paths2 = spec.paths) == null || (_spec$paths2 = _spec$paths2[pathName]) == null ? void 0 : _spec$paths2.servers;
311 const rootLevelServers = spec == null ? void 0 : spec.servers;
312 servers = isNonEmptyServerList(operationLevelServers) // eslint-disable-line no-nested-ternary
313 ? operationLevelServers : isNonEmptyServerList(pathItemLevelServers) // eslint-disable-line no-nested-ternary
314 ? pathItemLevelServers : isNonEmptyServerList(rootLevelServers) ? rootLevelServers : [_constants.DEFAULT_OPENAPI_3_SERVER];
315
316 // pick the first server that matches the server url
317 if (server) {
318 selectedServerObj = servers.find(srv => srv.url === server);
319 if (selectedServerObj) selectedServerUrl = server;
320 }
321
322 // default to the first server if we don't have one by now
323 if (!selectedServerUrl) {
324 [selectedServerObj] = servers;
325 selectedServerUrl = selectedServerObj.url;
326 }
327 if (selectedServerUrl.includes('{')) {
328 // do variable substitution
329 const varNames = getVariableTemplateNames(selectedServerUrl);
330 varNames.forEach(variable => {
331 if (selectedServerObj.variables && selectedServerObj.variables[variable]) {
332 // variable is defined in server
333 const variableDefinition = selectedServerObj.variables[variable];
334 const variableValue = serverVariables[variable] || variableDefinition.default;
335 const re = new RegExp(`{${variable}}`, 'g');
336 selectedServerUrl = selectedServerUrl.replace(re, variableValue);
337 }
338 });
339 }
340 return buildOas3UrlWithContext(selectedServerUrl, contextUrl);
341}
342function buildOas3UrlWithContext(ourUrl = '', contextUrl = '') {
343 // relative server url should be resolved against contextUrl
344 const parsedUrl = ourUrl && contextUrl ? parseURIReference(_empty.url.resolve(contextUrl, ourUrl)) : parseURIReference(ourUrl);
345 const parsedContextUrl = parseURIReference(contextUrl);
346 const computedScheme = stripNonAlpha(parsedUrl.protocol) || stripNonAlpha(parsedContextUrl.protocol);
347 const computedHost = parsedUrl.host || parsedContextUrl.host;
348 const computedPath = parsedUrl.pathname;
349 let res;
350 if (computedScheme && computedHost) {
351 res = `${computedScheme}://${computedHost + computedPath}`;
352
353 // if last character is '/', trim it off
354 } else {
355 res = computedPath;
356 }
357 return res[res.length - 1] === '/' ? res.slice(0, -1) : res;
358}
359function getVariableTemplateNames(str) {
360 const results = [];
361 const re = /{([^}]+)}/g;
362 let text;
363
364 // eslint-disable-next-line no-cond-assign
365 while (text = re.exec(str)) {
366 results.push(text[1]);
367 }
368 return results;
369}
370
371// Compose the baseUrl ( scheme + host + basePath )
372function swagger2BaseUrl({
373 spec,
374 scheme,
375 contextUrl = ''
376}) {
377 const parsedContextUrl = parseURIReference(contextUrl);
378 const firstSchemeInSpec = Array.isArray(spec.schemes) ? spec.schemes[0] : null;
379 const computedScheme = scheme || firstSchemeInSpec || stripNonAlpha(parsedContextUrl.protocol) || 'http';
380 const computedHost = spec.host || parsedContextUrl.host || '';
381 const computedPath = spec.basePath || '';
382 let res;
383 if (computedScheme && computedHost) {
384 // we have what we need for an absolute URL
385 res = `${computedScheme}://${computedHost + computedPath}`;
386 } else {
387 // if not, a relative URL will have to do
388 res = computedPath;
389 }
390
391 // If last character is '/', trim it off
392 return res[res.length - 1] === '/' ? res.slice(0, -1) : res;
393}
Note: See TracBrowser for help on using the repository browser.