diff --git a/packages/fury-adapter-oas3-parser/lib/parser/oas/parseServerObject.js b/packages/fury-adapter-oas3-parser/lib/parser/oas/parseServerObject.js index 453a284cd..6be7e6a8a 100644 --- a/packages/fury-adapter-oas3-parser/lib/parser/oas/parseServerObject.js +++ b/packages/fury-adapter-oas3-parser/lib/parser/oas/parseServerObject.js @@ -15,6 +15,37 @@ const parseServerVariableObject = require('./parseServerVariableObject'); const name = 'Server Object'; const requiredKeys = ['url']; +const validateVariablesInURL = (context, object) => { + const url = object.getValue('url'); + const variables = object.get('variables'); + const parseResult = new context.namespace.elements.ParseResult(); + + const urlVariables = url + .match(/{(.*?)}/g) + .map(x => x.replace(/[{}]/g, '')); + + // if you define a variable that is not in URL it warns (and the variable is ignored). + variables.keys().forEach((key) => { + if (!urlVariables.includes(key)) { + parseResult.push(createWarning(context.namespace, + `Server variable '${key}' is not present in the URL and will be ignored`, variables)); + + variables.remove(key); + } + }); + + // if you place a variable in the URL and its not in variables you get a warning that the variable is missing. + urlVariables.forEach((key) => { + if (!variables.hasKey(key)) { + parseResult.push(createWarning(context.namespace, + `URL variable '${key}' is missing within the server variables`, object.get('url'))); + } + }); + + parseResult.push(object); + return parseResult; +}; + const parseMember = context => R.cond([ [hasKey('description'), parseString(context, name, false)], [hasKey('url'), parseString(context, name, true)], @@ -23,6 +54,8 @@ const parseMember = context => R.cond([ [R.T, createInvalidMemberWarning(context.namespace, name)], ]); +const hasVariables = object => object.hasKey('variables'); + /** * Parse the OpenAPI 'Server Object' (`#/server`) * @see http://spec.openapis.org/oas/v3.0.3#server-object @@ -32,6 +65,7 @@ const parseMember = context => R.cond([ const parseServerObject = context => pipeParseResult(context.namespace, R.unless(isObject, createWarning(context.namespace, `'${name}' is not an object`)), parseObject(context, name, parseMember(context), requiredKeys, [], true), + R.when(hasVariables, R.curry(validateVariablesInURL)(context)), (object) => { const resource = new context.namespace.elements.Resource(); diff --git a/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseServerObject-test.js b/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseServerObject-test.js index 34b485956..6afbee286 100644 --- a/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseServerObject-test.js +++ b/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseServerObject-test.js @@ -102,6 +102,87 @@ describe('#parseServerObject', () => { expect(parseResult).to.contain.warning("'Server Object' 'variables' is not an object"); }); + it("warns when a variable in server 'variables' is not defined in the URL and removes it", () => { + const server = new namespace.elements.Object({ + url: 'https://{username}.gigantic-server.com/{version}/', + variables: { + username: { + default: 'Mario', + description: 'API user name', + }, + version: { + default: '1.0', + }, + location: { + default: 'Prague', + }, + }, + }); + + const parseResult = parse(context)(server); + expect(parseResult.length).to.equal(2); + expect(parseResult).to.contain.annotations; + expect(parseResult).to.contain.warning("Server variable 'location' is not present in the URL and will be ignored"); + + const resource = parseResult.get(0); + expect(resource).to.be.instanceof(namespace.elements.Resource); + + const { hrefVariables } = resource; + const firstHrefVariable = hrefVariables.content.content[0]; + const secondHrefVariable = hrefVariables.content.content[1]; + + expect(hrefVariables).to.be.instanceof(namespace.elements.HrefVariables); + expect(hrefVariables.length).to.equal(2); + + expect(firstHrefVariable).to.be.instanceof(namespace.elements.Member); + expect(firstHrefVariable.key.toValue()).to.equal('username'); + expect(firstHrefVariable.value.default).to.equal('Mario'); + expect(firstHrefVariable.value.description.toValue()).to.equal('API user name'); + + expect(secondHrefVariable).to.be.instanceof(namespace.elements.Member); + expect(secondHrefVariable.key.toValue()).to.equal('version'); + expect(secondHrefVariable.value.default).to.equal('1.0'); + }); + + it("warns when a URL defined variable is missing from 'variables'", () => { + const server = new namespace.elements.Object({ + url: 'https://{username}.{server}/{version}/', + variables: { + username: { + default: 'Mario', + description: 'API user name', + }, + version: { + default: '1.0', + }, + }, + }); + + const parseResult = parse(context)(server); + expect(parseResult.length).to.equal(2); + expect(parseResult).to.contain.annotations; + expect(parseResult).to.contain.warning("URL variable 'server' is missing within the server variables"); + + const resource = parseResult.get(0); + expect(resource).to.be.instanceof(namespace.elements.Resource); + + const { hrefVariables } = resource; + const firstHrefVariable = hrefVariables.content.content[0]; + const secondHrefVariable = hrefVariables.content.content[1]; + + expect(hrefVariables).to.be.instanceof(namespace.elements.HrefVariables); + expect(hrefVariables.length).to.equal(2); + + expect(firstHrefVariable).to.be.instanceof(namespace.elements.Member); + expect(firstHrefVariable.key.toValue()).to.equal('username'); + expect(firstHrefVariable.value.default).to.equal('Mario'); + expect(firstHrefVariable.value.description.toValue()).to.equal('API user name'); + + expect(secondHrefVariable).to.be.instanceof(namespace.elements.Member); + expect(secondHrefVariable.key.toValue()).to.equal('version'); + expect(secondHrefVariable.value.default).to.equal('1.0'); + }); + it('parse server object with variables', () => { const server = new namespace.elements.Object({ url: 'https://{username}.gigantic-server.com/{version}',