Skip to content

Commit

Permalink
fix(execute): handle Server Objects overrides for OpenAPI 2.0/3.0.x (#…
Browse files Browse the repository at this point in the history
…3221)

This change is specific to OpenAPI 2.0 and OpenAPI 3.0.x.

Refs #2967
  • Loading branch information
char0n authored Nov 3, 2023
1 parent 4682656 commit d45c9ab
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 27 deletions.
2 changes: 2 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const ACCEPT_HEADER_VALUE_FOR_DOCUMENTS = 'application/json, application/yaml';

export const DEFAULT_BASE_URL = 'https://swagger.io';

export const DEFAULT_OPENAPI_3_SERVER = Object.freeze({ url: '/' });
57 changes: 32 additions & 25 deletions src/execute/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import cookie from 'cookie';
import { isPlainObject } from 'is-plain-object';
import { url } from '@swagger-api/apidom-reference/configuration/empty';

import { DEFAULT_BASE_URL } from '../constants.js';
import { DEFAULT_BASE_URL, DEFAULT_OPENAPI_3_SERVER } from '../constants.js';
import stockHttp, { mergeInQueryOrForm } from '../http/index.js';
import createError from '../specmap/lib/create-error.js';
import SWAGGER2_PARAMETER_BUILDERS from './swagger2/parameter-builders.js';
Expand Down Expand Up @@ -319,40 +319,47 @@ export function baseUrl(obj) {
return specIsOAS3 ? oas3BaseUrl(obj) : swagger2BaseUrl(obj);
}

function oas3BaseUrl({ spec, pathName, method, server, contextUrl, serverVariables = {} }) {
const servers =
spec?.paths?.[pathName]?.[(method || '').toLowerCase()]?.servers ||
spec?.paths?.[pathName]?.servers ||
spec?.servers;
const isNonEmptyServerList = (value) => Array.isArray(value) && value.length > 0;

function oas3BaseUrl({ spec, pathName, method, server, contextUrl, serverVariables = {} }) {
let servers = [];
let selectedServerUrl = '';
let selectedServerObj = null;

if (server && servers && servers.length) {
const serverUrls = servers.map((srv) => srv.url);

if (serverUrls.indexOf(server) > -1) {
selectedServerUrl = server;
selectedServerObj = servers[serverUrls.indexOf(server)];
}
let selectedServerObj;

// compute the servers (this will be taken care of by ApiDOM refrator plugins in future
const operationLevelServers = spec?.paths?.[pathName]?.[(method || '').toLowerCase()]?.servers;
const pathItemLevelServers = spec?.paths?.[pathName]?.servers;
const rootLevelServers = spec?.servers;
servers = isNonEmptyServerList(operationLevelServers) // eslint-disable-line no-nested-ternary
? operationLevelServers
: isNonEmptyServerList(pathItemLevelServers) // eslint-disable-line no-nested-ternary
? pathItemLevelServers
: isNonEmptyServerList(rootLevelServers)
? rootLevelServers
: [DEFAULT_OPENAPI_3_SERVER];

// pick the first server that matches the server url
if (server) {
selectedServerObj = servers.find((srv) => srv.url === server);
if (selectedServerObj) selectedServerUrl = server;
}

if (!selectedServerUrl && servers && servers.length) {
// default to the first server if we don't have one by now
selectedServerUrl = servers[0].url; // eslint-disable-line semi
[selectedServerObj] = servers;
// default to the first server if we don't have one by now
if (!selectedServerUrl) {
selectedServerObj = servers.at(0);
selectedServerUrl = selectedServerObj.url;
}

if (selectedServerUrl.includes('{')) {
// do variable substitution
const varNames = getVariableTemplateNames(selectedServerUrl);
varNames.forEach((vari) => {
if (selectedServerObj.variables && selectedServerObj.variables[vari]) {
varNames.forEach((variable) => {
if (selectedServerObj.variables && selectedServerObj.variables[variable]) {
// variable is defined in server
const variableDefinition = selectedServerObj.variables[vari];
const variableValue = serverVariables[vari] || variableDefinition.default;
const variableDefinition = selectedServerObj.variables[variable];
const variableValue = serverVariables[variable] || variableDefinition.default;

const re = new RegExp(`{${vari}}`, 'g');
const re = new RegExp(`{${variable}}`, 'g');
selectedServerUrl = selectedServerUrl.replace(re, variableValue);
}
});
Expand All @@ -378,7 +385,7 @@ function buildOas3UrlWithContext(ourUrl = '', contextUrl = '') {
if (computedScheme && computedHost) {
res = `${computedScheme}://${computedHost + computedPath}`;

// If last character is '/', trim it off
// if last character is '/', trim it off
} else {
res = computedPath;
}
Expand Down
8 changes: 6 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable camelcase */
import { DEFAULT_OPENAPI_3_SERVER } from './constants.js';
import Http, { makeHttp, serializeRes, serializeHeaders } from './http/index.js';
import { makeResolve } from './resolver/index.js';
import { makeResolveSubtree } from './subtree-resolver/index.js';
Expand Down Expand Up @@ -135,6 +136,7 @@ Swagger.prototype.applyDefaults = function applyDefaults() {

if (isOpenAPI2(spec) && isHttpUrl(specUrl)) {
const parsed = new URL(specUrl);

if (!spec.host) {
spec.host = parsed.host;
}
Expand All @@ -145,8 +147,10 @@ Swagger.prototype.applyDefaults = function applyDefaults() {
spec.basePath = '/';
}
} else if (isOpenAPI3(spec)) {
if (!spec.servers || (Array.isArray(spec.servers) && spec.servers.length === 0)) {
spec.servers = [{ url: '/' }];
const isEmptyServerList = Array.isArray(spec.servers) && spec.servers.length === 0;

if (!spec.servers || isEmptyServerList) {
spec.servers = [DEFAULT_OPENAPI_3_SERVER];
}
}
};
Expand Down

0 comments on commit d45c9ab

Please sign in to comment.