From 15b8c6ef7275b5f86dfc78bd4f34fa11dc922fd3 Mon Sep 17 00:00:00 2001 From: Matheus Lichtnow Date: Mon, 20 Jan 2020 17:35:18 -0800 Subject: [PATCH] feat(handler): added handler for must contain domain and context and it tests --- .../data/with-domain-and-context/swagger.yml | 59 ++++++++++++++++++ .../swagger.yml | 60 ++++++++++++++++++ .../without-domain-and-context/swagger.yml | 59 ++++++++++++++++++ .../swagger.yml | 59 ++++++++++++++++++ .../must-contain-domain-and-context.spec.ts | 62 +++++++++++++++++++ src/rules/handlers/index.ts | 4 +- .../must-contain-domain-and-context.ts | 47 ++++++++++++++ src/rules/handlers/must-contain-port.ts | 1 - 8 files changed, 349 insertions(+), 2 deletions(-) create mode 100644 src/__tests__/data/with-domain-and-context/swagger.yml create mode 100644 src/__tests__/data/with-domain-context-and-version/swagger.yml create mode 100644 src/__tests__/data/without-domain-and-context/swagger.yml create mode 100644 src/__tests__/data/without-domain-and-with-context/swagger.yml create mode 100644 src/__tests__/rules/handlers/must-contain-domain-and-context.spec.ts create mode 100644 src/rules/handlers/must-contain-domain-and-context.ts diff --git a/src/__tests__/data/with-domain-and-context/swagger.yml b/src/__tests__/data/with-domain-and-context/swagger.yml new file mode 100644 index 0000000..05c620d --- /dev/null +++ b/src/__tests__/data/with-domain-and-context/swagger.yml @@ -0,0 +1,59 @@ +openapi: 3.0.1 +servers: + - url: 'https://api.geodatasource.com/domain/context' +info: + contact: + x-twitter: _geodatasource + description: 'GeoDataSourceâ„¢ Web Service is a REST API enable user to lookup for a city by using latitude and longitude coordinate. It will return the result in either JSON or XML containing the information of country, region, city, latitude and longitude. Visit https://www.geodatasource.com/web-service for further information.' + title: GeoDataSource Location Search + version: '1.0' + x-apisguru-categories: + - location + x-logo: + url: 'https://api.apis.guru/v2/cache/logo/https_twitter.com__geodatasource_profile_image.png' + x-origin: + - converter: + url: 'https://github.com/lucybot/api-spec-converter' + version: 2.7.31 + format: openapi + url: 'https://app.swaggerhub.com/apiproxy/schema/file/geodatasource/geodatasource-location-search/1.0/swagger.yaml' + version: '3.0' + x-preferred: true + x-providerName: geodatasource.com +paths: + /city: + get: + description: Get City name by using latitude and longitude + parameters: + - in: query + name: key + required: true + schema: + type: string + - in: query + name: lng + required: true + schema: + type: number + - in: query + name: lat + required: true + schema: + type: number + - in: query + name: format + schema: + enum: + - json + - xml + type: string + responses: + '200': + content: + application/json; charset=utf-8: + examples: + '0': + value: '{"country":"","region":"","city":"","latitude":"","longitude":""}' + schema: + type: string + description: Get response from longitude latitude lookup diff --git a/src/__tests__/data/with-domain-context-and-version/swagger.yml b/src/__tests__/data/with-domain-context-and-version/swagger.yml new file mode 100644 index 0000000..6e2a03d --- /dev/null +++ b/src/__tests__/data/with-domain-context-and-version/swagger.yml @@ -0,0 +1,60 @@ +openapi: 3.0.1 +servers: + - url: 'https://api.geodatasource.com/domain/context/v1' + - url: 'https://api.geodatasource.com/v1/domain/context' +info: + contact: + x-twitter: _geodatasource + description: 'GeoDataSourceâ„¢ Web Service is a REST API enable user to lookup for a city by using latitude and longitude coordinate. It will return the result in either JSON or XML containing the information of country, region, city, latitude and longitude. Visit https://www.geodatasource.com/web-service for further information.' + title: GeoDataSource Location Search + version: '1.0' + x-apisguru-categories: + - location + x-logo: + url: 'https://api.apis.guru/v2/cache/logo/https_twitter.com__geodatasource_profile_image.png' + x-origin: + - converter: + url: 'https://github.com/lucybot/api-spec-converter' + version: 2.7.31 + format: openapi + url: 'https://app.swaggerhub.com/apiproxy/schema/file/geodatasource/geodatasource-location-search/1.0/swagger.yaml' + version: '3.0' + x-preferred: true + x-providerName: geodatasource.com +paths: + /city: + get: + description: Get City name by using latitude and longitude + parameters: + - in: query + name: key + required: true + schema: + type: string + - in: query + name: lng + required: true + schema: + type: number + - in: query + name: lat + required: true + schema: + type: number + - in: query + name: format + schema: + enum: + - json + - xml + type: string + responses: + '200': + content: + application/json; charset=utf-8: + examples: + '0': + value: '{"country":"","region":"","city":"","latitude":"","longitude":""}' + schema: + type: string + description: Get response from longitude latitude lookup diff --git a/src/__tests__/data/without-domain-and-context/swagger.yml b/src/__tests__/data/without-domain-and-context/swagger.yml new file mode 100644 index 0000000..bcb49ba --- /dev/null +++ b/src/__tests__/data/without-domain-and-context/swagger.yml @@ -0,0 +1,59 @@ +openapi: 3.0.1 +servers: + - url: 'https://api.geodatasource.com' +info: + contact: + x-twitter: _geodatasource + description: 'GeoDataSourceâ„¢ Web Service is a REST API enable user to lookup for a city by using latitude and longitude coordinate. It will return the result in either JSON or XML containing the information of country, region, city, latitude and longitude. Visit https://www.geodatasource.com/web-service for further information.' + title: GeoDataSource Location Search + version: '1.0' + x-apisguru-categories: + - location + x-logo: + url: 'https://api.apis.guru/v2/cache/logo/https_twitter.com__geodatasource_profile_image.png' + x-origin: + - converter: + url: 'https://github.com/lucybot/api-spec-converter' + version: 2.7.31 + format: openapi + url: 'https://app.swaggerhub.com/apiproxy/schema/file/geodatasource/geodatasource-location-search/1.0/swagger.yaml' + version: '3.0' + x-preferred: true + x-providerName: geodatasource.com +paths: + /city: + get: + description: Get City name by using latitude and longitude + parameters: + - in: query + name: key + required: true + schema: + type: string + - in: query + name: lng + required: true + schema: + type: number + - in: query + name: lat + required: true + schema: + type: number + - in: query + name: format + schema: + enum: + - json + - xml + type: string + responses: + '200': + content: + application/json; charset=utf-8: + examples: + '0': + value: '{"country":"","region":"","city":"","latitude":"","longitude":""}' + schema: + type: string + description: Get response from longitude latitude lookup diff --git a/src/__tests__/data/without-domain-and-with-context/swagger.yml b/src/__tests__/data/without-domain-and-with-context/swagger.yml new file mode 100644 index 0000000..42c8e9f --- /dev/null +++ b/src/__tests__/data/without-domain-and-with-context/swagger.yml @@ -0,0 +1,59 @@ +openapi: 3.0.1 +servers: + - url: 'https://api.geodatasource.com/context' +info: + contact: + x-twitter: _geodatasource + description: 'GeoDataSourceâ„¢ Web Service is a REST API enable user to lookup for a city by using latitude and longitude coordinate. It will return the result in either JSON or XML containing the information of country, region, city, latitude and longitude. Visit https://www.geodatasource.com/web-service for further information.' + title: GeoDataSource Location Search + version: '1.0' + x-apisguru-categories: + - location + x-logo: + url: 'https://api.apis.guru/v2/cache/logo/https_twitter.com__geodatasource_profile_image.png' + x-origin: + - converter: + url: 'https://github.com/lucybot/api-spec-converter' + version: 2.7.31 + format: openapi + url: 'https://app.swaggerhub.com/apiproxy/schema/file/geodatasource/geodatasource-location-search/1.0/swagger.yaml' + version: '3.0' + x-preferred: true + x-providerName: geodatasource.com +paths: + /city: + get: + description: Get City name by using latitude and longitude + parameters: + - in: query + name: key + required: true + schema: + type: string + - in: query + name: lng + required: true + schema: + type: number + - in: query + name: lat + required: true + schema: + type: number + - in: query + name: format + schema: + enum: + - json + - xml + type: string + responses: + '200': + content: + application/json; charset=utf-8: + examples: + '0': + value: '{"country":"","region":"","city":"","latitude":"","longitude":""}' + schema: + type: string + description: Get response from longitude latitude lookup diff --git a/src/__tests__/rules/handlers/must-contain-domain-and-context.spec.ts b/src/__tests__/rules/handlers/must-contain-domain-and-context.spec.ts new file mode 100644 index 0000000..d11e87f --- /dev/null +++ b/src/__tests__/rules/handlers/must-contain-domain-and-context.spec.ts @@ -0,0 +1,62 @@ +import path from 'path'; +import { parse } from '../../../index'; +import { mustContainDomainAndContext } from '../../../rules/handlers'; +import { RuleFault } from '../../../rules/rule-fault'; + +describe('mustContainDomainAndContext function', () => { + const apiFileWithoutServer = path.join(__dirname, '..', '..', 'data', 'without-server-url', 'swagger.yml'); + const apiFileWithDomainAndcontext = path.join(__dirname, '..', '..', 'data', 'with-domain-and-context', 'swagger.yml'); + const apiFileWithDomaincontextAndVersion = path.join(__dirname, '..', '..', 'data', 'with-domain-context-and-version', 'swagger.yml'); + const apiFileWithoutDomainAndContext = path.join(__dirname, '..', '..', 'data', 'without-domain-and-context', 'swagger.yml'); + const apiFileWithoutDomainAndWithContext = path.join(__dirname, '..', '..', 'data', 'without-domain-and-with-context', 'swagger.yml'); + + it('should return when no server is present', async () => { + const api = await parse(apiFileWithoutServer); + + const faults: RuleFault[] = []; + + mustContainDomainAndContext(api, faults); + + expect(faults.length).toBe(0); + }); + + it('should have no faults when domain and context are present', async () => { + const api = await parse(apiFileWithDomainAndcontext); + + const faults: RuleFault[] = []; + + mustContainDomainAndContext(api, faults); + + expect(faults.length).toBe(0); + }); + + it('should have no faults when domain, context and version are present', async () => { + const api = await parse(apiFileWithDomaincontextAndVersion); + + const faults: RuleFault[] = []; + + mustContainDomainAndContext(api, faults); + + expect(faults.length).toBe(0); + }); + + it('should have one fault when domain and context are not present', async () => { + const api = await parse(apiFileWithoutDomainAndContext); + + const faults: RuleFault[] = []; + + mustContainDomainAndContext(api, faults); + + expect(faults.length).toBe(1); + }); + + it('should have one fault when domain is not present and context is', async () => { + const api = await parse(apiFileWithoutDomainAndWithContext); + + const faults: RuleFault[] = []; + + mustContainDomainAndContext(api, faults); + + expect(faults.length).toBe(1); + }); +}); diff --git a/src/rules/handlers/index.ts b/src/rules/handlers/index.ts index d35bbe4..43ee479 100644 --- a/src/rules/handlers/index.ts +++ b/src/rules/handlers/index.ts @@ -2,10 +2,12 @@ import { mustContainServerURL } from './must-contain-server-url'; import { mustContainPort } from './must-contain-port'; import { noSingularResource } from './no-singular-resource'; import { mustContainVersion } from './must-contain-version'; +import { mustContainDomainAndContext } from './must-contain-domain-and-context'; export { mustContainServerURL, mustContainPort, noSingularResource, - mustContainVersion + mustContainVersion, + mustContainDomainAndContext }; diff --git a/src/rules/handlers/must-contain-domain-and-context.ts b/src/rules/handlers/must-contain-domain-and-context.ts new file mode 100644 index 0000000..8f0fbf6 --- /dev/null +++ b/src/rules/handlers/must-contain-domain-and-context.ts @@ -0,0 +1,47 @@ +import { OpenAPI } from "openapi-types"; +import Url from "url-parse"; +import { RuleFault, Severity, RuleFaultContent } from "../rule-fault"; +import { produceRuleFaultValueForUrl, pushFault } from './util'; + +const faults = { + mustContainDomainAndContext: 'Missing domain and/or context on url property' +}; + +const produceMustContainDomainAndContext = (urlString: string): RuleFault => { + return { + value: produceRuleFaultValueForUrl(urlString), + errors: [ + { + severity: Severity.warning, + message: faults.mustContainDomainAndContext + } as RuleFaultContent + ] + }; +}; + +const isMissingDomainAndContext = (urlString: string): boolean => { + const url = new Url(urlString); + + /** + * Matches /domain/context but excludes the version on the test which matches `/v\w+/` + */ + const matcher = /\/(?!(v\d+)\b)\w+\/(?!(v\d+)\b)\w+/i; + return !matcher.test(url.pathname); +}; + +export const mustContainDomainAndContext = (api: OpenAPI.Document, ruleFaults: RuleFault[]) => { + const apiParsed: any = api; + + /** + * Without any url, there is no way to evaluate port + */ + if (!apiParsed.servers) { + return; + } + + apiParsed.servers.forEach((server: any) => { + if (isMissingDomainAndContext(server.url)) { + pushFault(produceMustContainDomainAndContext(server.url), ruleFaults); + } + }); +}; diff --git a/src/rules/handlers/must-contain-port.ts b/src/rules/handlers/must-contain-port.ts index 918dcb4..2228a2a 100644 --- a/src/rules/handlers/must-contain-port.ts +++ b/src/rules/handlers/must-contain-port.ts @@ -39,5 +39,4 @@ export const mustContainPort = (api: OpenAPI.Document, ruleFaults: RuleFault[]) pushFault(produceMustContainPort(server.url), ruleFaults); } }); - };