diff --git a/packages/http-server/src/server.ts b/packages/http-server/src/server.ts index c312ecd24..3b7403916 100644 --- a/packages/http-server/src/server.ts +++ b/packages/http-server/src/server.ts @@ -7,12 +7,12 @@ import { createInstance, IHttpConfig } from '@stoplight/prism-http'; // TODO: this is a trivial example, scratch code const prism = createInstance({ - config: async ({ query }) => { + config: async ({ url }) => { const config: IHttpConfig = {}; - if (query && query.__code) { + if (url.query && url.query.__code) { config.mock = { - code: query.__code, + code: url.query.__code, }; } @@ -21,7 +21,10 @@ const prism = createInstance({ }); app.get('*', async (req: any, res: any) => { - const response = await prism.process({ method: req.method, host: req.host, path: req.path }); + const response = await prism.process({ + method: req.method, + url: { baseUrl: req.host, path: req.path }, + }); if (response.data) { res.send(response.data); diff --git a/packages/http/src/router/__tests__/index.spec.ts b/packages/http/src/router/__tests__/index.spec.ts index 474e7cf83..9039c0614 100644 --- a/packages/http/src/router/__tests__/index.spec.ts +++ b/packages/http/src/router/__tests__/index.spec.ts @@ -12,7 +12,7 @@ import { pickOneHttpMethod, pickSetOfHttpMethods, randomPath } from './utils'; const chance = new Chance(); -function createResource(method: string, path: string, servers: IServer[] = []): IHttpOperation { +function createResource(method: string, path: string, servers?: IServer[]): IHttpOperation { return { id: chance.guid(), method, @@ -41,6 +41,23 @@ describe('http router', () => { describe('given a resource', () => { test('should not match if no server defined', () => { + const method = pickOneHttpMethod(); + const path = randomPath(); + const resourcePromise = router.route({ + resources: [createResource(method, path, [])], + input: { + method, + url: { + baseUrl: '', + path, + }, + }, + }); + + return expect(resourcePromise).rejects.toBe(NO_SERVER_CONFIGURATION_PROVIDED_ERROR); + }); + + test('should not match if no servers arrays provided', () => { const method = pickOneHttpMethod(); const path = randomPath(); const resourcePromise = router.route({ @@ -128,6 +145,60 @@ describe('http router', () => { expect(resource).toBe(expectedResource); }); + test('given a templated matching server and matched concrete path should match', async () => { + const url = 'http://{host}/v1'; + const path = randomPath({ includeTemplates: false }); + const expectedResource = createResource(method, path, [ + { + url, + variables: { + host: { + default: 'stoplight.io', + }, + }, + }, + ]); + const resource = await router.route({ + resources: [expectedResource], + input: { + method, + url: { + baseUrl: 'http://stoplight.io/v1', + path, + }, + }, + }); + + expect(resource).toBe(expectedResource); + }); + + test('given a templated matching server and matched templated path should match', async () => { + const url = 'http://{host}/v1'; + const path = '/{x}/b'; + const expectedResource = createResource(method, path, [ + { + url, + variables: { + host: { + default: 'stoplight.io', + }, + }, + }, + ]); + const resource = await router.route({ + resources: [expectedResource], + input: { + method, + url: { + baseUrl: 'http://stoplight.io/v1', + path: '/a/b', + }, + }, + }); + + expect(resource).toBe(expectedResource); + }); + test('given a concrete matching server and matched templated path should match', async () => { const url = chance.url(); const templatedPath = '/a/{b}/c'; @@ -292,6 +363,22 @@ describe('http router', () => { expect(resource).toBe(expectedResource); }); + + test('given no baseUrl and a server url it should ignore servers and match by path', async () => { + const path = randomPath({ includeTemplates: false }); + const expectedResource = createResource(method, path, [{ url: 'www.stoplight.io/v1' }]); + const resource = await router.route({ + resources: [expectedResource], + input: { + method, + url: { + path, + }, + }, + }); + + expect(resource).toBe(expectedResource); + }); }); }); }); diff --git a/packages/http/src/router/errors.ts b/packages/http/src/router/errors.ts index 615371448..82f2bc58b 100644 --- a/packages/http/src/router/errors.ts +++ b/packages/http/src/router/errors.ts @@ -1,4 +1,3 @@ -export const ROUTE_DISAMBIGUATION_ERROR = new Error('Could not disambiguate the given route.'); export const NO_RESOURCE_PROVIDED_ERROR = new Error('Route not resolved, no resource provided.'); export const NONE_METHOD_MATCHED_ERROR = new Error('Route not resolved, none method matched.'); export const NONE_PATH_MATCHED_ERROR = new Error('Route not resolved, none path matched.'); diff --git a/packages/http/src/router/index.ts b/packages/http/src/router/index.ts index 7d9768216..7c3e4463f 100644 --- a/packages/http/src/router/index.ts +++ b/packages/http/src/router/index.ts @@ -1,5 +1,5 @@ import { IRouter } from '@stoplight/prism-core'; -import { IHttpOperation } from '@stoplight/types'; +import { IHttpOperation, IServer } from '@stoplight/types'; import { IHttpConfig, IHttpRequest } from '../types'; import { @@ -8,7 +8,6 @@ import { NONE_METHOD_MATCHED_ERROR, NONE_PATH_MATCHED_ERROR, NONE_SERVER_MATCHED_ERROR, - ROUTE_DISAMBIGUATION_ERROR, } from './errors'; import { matchBaseUrl } from './matchBaseUrl'; import { matchPath } from './matchPath'; @@ -18,6 +17,7 @@ export const router: IRouter = { route: async ({ resources, input }) => { const matches = []; const { path: requestPath, baseUrl: requestBaseUrl } = input.url; + const ignoreServers: boolean = requestBaseUrl === undefined; if (!resources.length) { throw NO_RESOURCE_PROVIDED_ERROR; @@ -26,38 +26,31 @@ export const router: IRouter = { let noServerProvided: boolean = true; let noneMethodMatched: boolean = true; let nonePathMatched: boolean = true; - let noneServerMatched: boolean = true; + let noneServerMatched: boolean = !ignoreServers; for (const resource of resources) { if (!matchByMethod(input, resource)) continue; noneMethodMatched = false; const pathMatch = matchPath(requestPath, resource.path); - const serverMatches = []; - const { servers = [] } = resource; if (servers.length) noServerProvided = false; if (pathMatch !== MatchType.NOMATCH) nonePathMatched = false; - for (const server of servers) { - const tempServerMatch = matchBaseUrl(server, requestBaseUrl); - if (tempServerMatch !== MatchType.NOMATCH) { - serverMatches.push(tempServerMatch); - } + let serverMatch: MatchType | null = null; + + if (!ignoreServers) { + serverMatch = matchServer(servers, requestBaseUrl as string); + if (serverMatch) noneServerMatched = false; } - const serverMatch = disambiguateServers(serverMatches); - - if (serverMatch) { - noneServerMatched = false; - if (pathMatch !== MatchType.NOMATCH) { - matches.push({ - pathMatch, - serverMatch, - resource, - }); - } + if (pathMatch !== MatchType.NOMATCH) { + matches.push({ + pathMatch, + serverMatch, + resource, + }); } } @@ -81,6 +74,18 @@ export const router: IRouter = { }, }; +function matchServer(servers: IServer[], requestBaseUrl: string) { + const serverMatches = []; + for (const server of servers) { + const tempServerMatch = matchBaseUrl(server, requestBaseUrl); + if (tempServerMatch !== MatchType.NOMATCH) { + serverMatches.push(tempServerMatch); + } + } + + return disambiguateServers(serverMatches); +} + function matchByMethod(request: IHttpRequest, operation: IHttpOperation): boolean { return operation.method.toLowerCase() === request.method.toLowerCase(); } @@ -96,15 +101,17 @@ function disambiguateMatches(matches: IMatch[]): IHttpOperation { // then fallback to first matches[0]; - if (!matchResult) { - throw ROUTE_DISAMBIGUATION_ERROR; - } - return matchResult.resource; } function areServerAndPath(match: IMatch, serverType: MatchType, pathType: MatchType) { - return match.serverMatch === serverType && match.pathMatch === pathType; + const serverMatch = match.serverMatch; + if (serverMatch === null) { + // server match will only be null if server matching is disabled. + // therefore skip comparison. + return match.pathMatch === pathType; + } + return serverMatch === serverType && match.pathMatch === pathType; } /** diff --git a/packages/http/src/router/types.ts b/packages/http/src/router/types.ts index ce3c8e11c..349277ca8 100644 --- a/packages/http/src/router/types.ts +++ b/packages/http/src/router/types.ts @@ -4,7 +4,7 @@ export type Nullable = T | null; export interface IMatch { resource: IHttpOperation; - serverMatch: MatchType; + serverMatch: MatchType | null; pathMatch: MatchType; } diff --git a/packages/http/src/types.ts b/packages/http/src/types.ts index 4fc67eb9c..535ede91e 100644 --- a/packages/http/src/types.ts +++ b/packages/http/src/types.ts @@ -47,7 +47,7 @@ export interface IHttpConfig extends IPrismConfig { export interface IHttpRequest { method: IHttpMethod; url: { - baseUrl: string; + baseUrl?: string; path: string; query?: { [name: string]: string;