Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(execute): handle Server Objects overrides for OpenAPI 2.0/3.0.x #3221

Merged
merged 2 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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