Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Commit 2dcde2d

Browse files
author
Marco Friso
authored
feat(oas3): validation server variables against URL (#440)
1 parent 2141007 commit 2dcde2d

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

packages/fury-adapter-oas3-parser/lib/parser/oas/parseServerObject.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,37 @@ const parseServerVariableObject = require('./parseServerVariableObject');
1515
const name = 'Server Object';
1616
const requiredKeys = ['url'];
1717

18+
const validateVariablesInURL = (context, object) => {
19+
const url = object.getValue('url');
20+
const variables = object.get('variables');
21+
const parseResult = new context.namespace.elements.ParseResult();
22+
23+
const urlVariables = url
24+
.match(/{(.*?)}/g)
25+
.map(x => x.replace(/[{}]/g, ''));
26+
27+
// if you define a variable that is not in URL it warns (and the variable is ignored).
28+
variables.keys().forEach((key) => {
29+
if (!urlVariables.includes(key)) {
30+
parseResult.push(createWarning(context.namespace,
31+
`Server variable '${key}' is not present in the URL and will be ignored`, variables));
32+
33+
variables.remove(key);
34+
}
35+
});
36+
37+
// if you place a variable in the URL and its not in variables you get a warning that the variable is missing.
38+
urlVariables.forEach((key) => {
39+
if (!variables.hasKey(key)) {
40+
parseResult.push(createWarning(context.namespace,
41+
`URL variable '${key}' is missing within the server variables`, object.get('url')));
42+
}
43+
});
44+
45+
parseResult.push(object);
46+
return parseResult;
47+
};
48+
1849
const parseMember = context => R.cond([
1950
[hasKey('description'), parseString(context, name, false)],
2051
[hasKey('url'), parseString(context, name, true)],
@@ -23,6 +54,8 @@ const parseMember = context => R.cond([
2354
[R.T, createInvalidMemberWarning(context.namespace, name)],
2455
]);
2556

57+
const hasVariables = object => object.hasKey('variables');
58+
2659
/**
2760
* Parse the OpenAPI 'Server Object' (`#/server`)
2861
* @see http://spec.openapis.org/oas/v3.0.3#server-object
@@ -32,6 +65,7 @@ const parseMember = context => R.cond([
3265
const parseServerObject = context => pipeParseResult(context.namespace,
3366
R.unless(isObject, createWarning(context.namespace, `'${name}' is not an object`)),
3467
parseObject(context, name, parseMember(context), requiredKeys, [], true),
68+
R.when(hasVariables, R.curry(validateVariablesInURL)(context)),
3569
(object) => {
3670
const resource = new context.namespace.elements.Resource();
3771

packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseServerObject-test.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,87 @@ describe('#parseServerObject', () => {
102102
expect(parseResult).to.contain.warning("'Server Object' 'variables' is not an object");
103103
});
104104

105+
it("warns when a variable in server 'variables' is not defined in the URL and removes it", () => {
106+
const server = new namespace.elements.Object({
107+
url: 'https://{username}.gigantic-server.com/{version}/',
108+
variables: {
109+
username: {
110+
default: 'Mario',
111+
description: 'API user name',
112+
},
113+
version: {
114+
default: '1.0',
115+
},
116+
location: {
117+
default: 'Prague',
118+
},
119+
},
120+
});
121+
122+
const parseResult = parse(context)(server);
123+
expect(parseResult.length).to.equal(2);
124+
expect(parseResult).to.contain.annotations;
125+
expect(parseResult).to.contain.warning("Server variable 'location' is not present in the URL and will be ignored");
126+
127+
const resource = parseResult.get(0);
128+
expect(resource).to.be.instanceof(namespace.elements.Resource);
129+
130+
const { hrefVariables } = resource;
131+
const firstHrefVariable = hrefVariables.content.content[0];
132+
const secondHrefVariable = hrefVariables.content.content[1];
133+
134+
expect(hrefVariables).to.be.instanceof(namespace.elements.HrefVariables);
135+
expect(hrefVariables.length).to.equal(2);
136+
137+
expect(firstHrefVariable).to.be.instanceof(namespace.elements.Member);
138+
expect(firstHrefVariable.key.toValue()).to.equal('username');
139+
expect(firstHrefVariable.value.default).to.equal('Mario');
140+
expect(firstHrefVariable.value.description.toValue()).to.equal('API user name');
141+
142+
expect(secondHrefVariable).to.be.instanceof(namespace.elements.Member);
143+
expect(secondHrefVariable.key.toValue()).to.equal('version');
144+
expect(secondHrefVariable.value.default).to.equal('1.0');
145+
});
146+
147+
it("warns when a URL defined variable is missing from 'variables'", () => {
148+
const server = new namespace.elements.Object({
149+
url: 'https://{username}.{server}/{version}/',
150+
variables: {
151+
username: {
152+
default: 'Mario',
153+
description: 'API user name',
154+
},
155+
version: {
156+
default: '1.0',
157+
},
158+
},
159+
});
160+
161+
const parseResult = parse(context)(server);
162+
expect(parseResult.length).to.equal(2);
163+
expect(parseResult).to.contain.annotations;
164+
expect(parseResult).to.contain.warning("URL variable 'server' is missing within the server variables");
165+
166+
const resource = parseResult.get(0);
167+
expect(resource).to.be.instanceof(namespace.elements.Resource);
168+
169+
const { hrefVariables } = resource;
170+
const firstHrefVariable = hrefVariables.content.content[0];
171+
const secondHrefVariable = hrefVariables.content.content[1];
172+
173+
expect(hrefVariables).to.be.instanceof(namespace.elements.HrefVariables);
174+
expect(hrefVariables.length).to.equal(2);
175+
176+
expect(firstHrefVariable).to.be.instanceof(namespace.elements.Member);
177+
expect(firstHrefVariable.key.toValue()).to.equal('username');
178+
expect(firstHrefVariable.value.default).to.equal('Mario');
179+
expect(firstHrefVariable.value.description.toValue()).to.equal('API user name');
180+
181+
expect(secondHrefVariable).to.be.instanceof(namespace.elements.Member);
182+
expect(secondHrefVariable.key.toValue()).to.equal('version');
183+
expect(secondHrefVariable.value.default).to.equal('1.0');
184+
});
185+
105186
it('parse server object with variables', () => {
106187
const server = new namespace.elements.Object({
107188
url: 'https://{username}.gigantic-server.com/{version}',

0 commit comments

Comments
 (0)