Skip to content

Commit

Permalink
fix(execute): do not encode server variables by default
Browse files Browse the repository at this point in the history
This will allow Saas and On-Premise usecase to be handled correctly.
Encoding can be turned on again by providing
serverVariableEncoder option.

Refs #3656
  • Loading branch information
char0n committed Sep 13, 2024
1 parent df83852 commit 6a151d9
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 5 deletions.
1 change: 1 addition & 0 deletions docs/usage/http-client-for-oas-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Property | Description
`userFetch` | `Function=cross-fetch`. Custom **asynchronous** fetch function that accepts two arguments: the `url` and the `Request` object and must return a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. More info in [HTTP Client](http-client.md) documentation.
`signal` | `AbortSignal=null`. AbortSignal object instance, which can be used to abort a request as desired.
`server` | `String`. URL (`https://example.com`) or relative URI Reference (`/path/subpath`). Must match with of the defined `Server Objects`. If matched, it will be prepended to every requested path.
`serverVariableEncoder` | `Function=identity`. An encoder function that is run on a server variable before substituted to the URL template.
`contextUrl` | `String`. URL, e.g. `https://example.com`. Used in following situations: <br /><br />If `server` option is not matched and there is no `Server Object` defined in the definition, this URL will be prepended to every requested path.<br /><br />If matched `Server Object` is defined as relative URI Reference its `url` fixed field is resolved against `contenxtUrl`. Resolved URL will be prepended to every requested path.

For all later references, we will always use following OpenAPI 3.0.0 definition when referring
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"node-fetch-commonjs": "^3.3.2",
"openapi-path-templating": "^1.5.1",
"openapi-server-url-templating": "^1.0.0",
"ramda": "^0.30.1",
"ramda-adjunct": "^5.0.0",
"neotraverse": "=0.6.18"
},
Expand Down
25 changes: 20 additions & 5 deletions src/execute/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import cookie from 'cookie';
import { identity } from 'ramda';
import { isPlainObject } from 'ramda-adjunct';
import {
test as testServerURLTemplate,
Expand Down Expand Up @@ -129,6 +130,7 @@ export function buildRequest(options) {
serverVariables,
http,
signal,
serverVariableEncoder,
} = options;

let { parameters, parameterBuilders } = options;
Expand Down Expand Up @@ -183,6 +185,7 @@ export function buildRequest(options) {
serverVariables,
pathName,
method,
serverVariableEncoder,
});

req.url += baseURL;
Expand Down Expand Up @@ -321,7 +324,15 @@ export function baseUrl(obj) {

const isNonEmptyServerList = (value) => Array.isArray(value) && value.length > 0;

function oas3BaseUrl({ spec, pathName, method, server, contextUrl, serverVariables = {} }) {
function oas3BaseUrl({
spec,
pathName,
method,
server,
contextUrl,
serverVariables = {},
serverVariableEncoder,
}) {
let servers = [];
let selectedServerUrl = '';
let selectedServerObj;
Expand Down Expand Up @@ -359,10 +370,14 @@ function oas3BaseUrl({ spec, pathName, method, server, contextUrl, serverVariabl
{}
);

selectedServerUrl = substituteServerURLTemplate(selectedServerUrl, {
...selectedServerVariables,
...serverVariables,
});
selectedServerUrl = substituteServerURLTemplate(
selectedServerUrl,
{
...selectedServerVariables,
...serverVariables,
},
{ encoder: typeof serverVariableEncoder === 'function' ? serverVariableEncoder : identity }
);
}

return buildOas3UrlWithContext(selectedServerUrl, contextUrl);
Expand Down
157 changes: 157 additions & 0 deletions test/execute/server-variable-encoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { execute, buildRequest } from '../../src/execute/index.js';

describe('execute/serverVariableEncoder', () => {
test('should encode when encoder provided', () => {
const spec = {
openapi: '3.0.3',
servers: [
{
url: '{server}/v1',
variables: {
server: {
default: 'https://swagger.io',
},
},
},
],
paths: {
'/one': {
get: {
operationId: 'getMe',
parameters: [{ name: 'petId', in: 'query' }],
},
},
},
};

const spy = jest.fn().mockImplementation(() => Promise.resolve());

execute({
fetch: spy,
spec,
operationId: 'getMe',
serverVariableEncoder: encodeURIComponent,
});

expect(spy.mock.calls.length).toEqual(1);
expect(spy.mock.calls[0][0]).toEqual({
method: 'GET',
url: 'https%3A%2F%2Fswagger.io/v1/one',
credentials: 'same-origin',
headers: {},
});
});

test('should not encode when encoder not provided', () => {
const spec = {
openapi: '3.0.3',
servers: [
{
url: '{server}/v1',
variables: {
server: {
default: 'https://swagger.io',
},
},
},
],
paths: {
'/one': {
get: {
operationId: 'getMe',
parameters: [{ name: 'petId', in: 'query' }],
},
},
},
};

const spy = jest.fn().mockImplementation(() => Promise.resolve());

execute({
fetch: spy,
spec,
operationId: 'getMe',
});

expect(spy.mock.calls.length).toEqual(1);
expect(spy.mock.calls[0][0]).toEqual({
method: 'GET',
url: 'https://swagger.io/v1/one',
credentials: 'same-origin',
headers: {},
});
});
});

describe('buildRequest/serverVariableEncoder', () => {
test('should encode when encoder provided', () => {
const spec = {
openapi: '3.0.3',
servers: [
{
url: '{server}/v1',
variables: {
server: {
default: 'https://swagger.io',
},
},
},
],
paths: {
'/one': {
get: {
operationId: 'getMe',
parameters: [{ name: 'petId', in: 'query' }],
},
},
},
};

const req = buildRequest({
spec,
operationId: 'getMe',
parameters: { petId: 123 },
serverVariableEncoder: encodeURIComponent,
});

expect(req).toEqual({
url: 'https%3A%2F%2Fswagger.io/v1/one?petId=123',
method: 'GET',
credentials: 'same-origin',
headers: {},
});
});

test('should not encode when encoder not provided', () => {
const spec = {
openapi: '3.0.3',
servers: [
{
url: '{server}/v1',
variables: {
server: {
default: 'https://swagger.io',
},
},
},
],
paths: {
'/one': {
get: {
operationId: 'getMe',
parameters: [{ name: 'petId', in: 'query' }],
},
},
},
};

const req = buildRequest({ spec, operationId: 'getMe', parameters: { petId: 123 } });

expect(req).toEqual({
url: 'https://swagger.io/v1/one?petId=123',
method: 'GET',
credentials: 'same-origin',
headers: {},
});
});
});

0 comments on commit 6a151d9

Please sign in to comment.