Skip to content

Commit

Permalink
Register all requests with the request handler, expose server.canHandle
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanto committed Feb 12, 2020
1 parent 4ec1917 commit 6eeb644
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 13 deletions.
55 changes: 55 additions & 0 deletions __tests__/external/shared/server/can-handle-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Server } from "miragejs";

describe("External | Shared | Server | canHandle", () => {
let server;

beforeEach(() => {
server = new Server({
environment: "test"
});
});

afterEach(function() {
server.shutdown();
});

test("its true when a route is defined", () => {
server.get("/movies", () => {
return [1, 2, 3];
});

expect(server.canHandle("get", "/movies")).toBeTrue();
});

test("its false when a route is not defined", () => {
expect(server.canHandle("get", "/movies")).toBeFalse();
});

test("it works for namespaces", () => {
server.namespace = "api";
server.get("/movies", () => {
return [1, 2, 3];
});

expect(server.canHandle("get", "/api/movies")).toBeTrue();
expect(server.canHandle("get", "/movies")).toBeFalse();
});

test("it works for urls on a different origin", () => {
server.urlPrefix = "https://example.com";
server.get("/movies", () => {
return [1, 2, 3];
});

expect(server.canHandle("get", "https://example.com/movies")).toBeTrue();
expect(server.canHandle("get", "/movies")).toBeFalse();
});

test("it works with dynamic segments", () => {
server.get("/movies/:id", () => {
return { id: 1 };
});

expect(server.canHandle("get", "/movies/1")).toBeTrue();
});
});
87 changes: 87 additions & 0 deletions lib/request-handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import RouteRecognizer from "route-recognizer";
import urlParse from "url-parse";

const defaultOrigin = Symbol();

/**
A class for storing and looking up information about route handlers registered with Mirage.
@class RequestHandler
@private
*/
export default class RequestHandler {
constructor(server) {
this.server = server;
this.originRoutes = {};
}

/**
A single group of route recognizers won't work because route recognizer has no concept of an origin. So we're going to use this function to group all of the recognizers by their origin.
@private
*/
recognizersFor(url) {
let { origin } = urlParse(url);
let key = origin || defaultOrigin;

if (!this.originRoutes[key]) {
let routes = {
GET: new RouteRecognizer(),
POST: new RouteRecognizer(),
PUT: new RouteRecognizer(),
PATCH: new RouteRecognizer(),
DELETE: new RouteRecognizer(),
OPTIONS: new RouteRecognizer()
};
routes.delete = routes.del;
this.originRoutes[key] = routes;
}

return this.originRoutes[key];
}

/**
The recognizer for the given verb and url
@private
*/
recognizerFor(verb, url) {
let recognizers = this.recognizersFor(url);
let method = verb.toUpperCase();
return recognizers[method];
}

/**
Adds a route handler.
@param {string} verb The HTTP verb to handle
@param {string} url The URL to attach the handler to
@param {handler} function The handler
@public
*/
register(verb, url, handler) {
let { pathname } = urlParse(url);
this.recognizerFor(verb, url).add([{ path: pathname, handler }]);
}

/**
@private
*/
routesFor(verb, url) {
let method = verb.toUpperCase();
let recognizer = this.recognizerFor(method, url);
let { pathname } = urlParse(url);
return recognizer.recognize(pathname) || [];
}

/**
Checks whether or not the verb and url can be handled by one of the registered handlers
@return {boolean} Is the verb/url registered
@public
*/
canHandle(verb, url) {
return this.routesFor(verb, url).length > 0;
}
}
38 changes: 27 additions & 11 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import isAssociation from "./utils/is-association";
import assert from "./assert";
import BelongsTo from "./orm/associations/belongs-to";
import Container from "./container";
import RequestHandler from "./request-handler";
import { singularize, pluralize } from "inflected";
import pick from "lodash.pick";
import assign from "lodash.assign";
Expand Down Expand Up @@ -209,6 +210,7 @@ export default class Server {
*/
constructor(options = {}) {
this._container = new Container();
this.requestHandler = new RequestHandler(this);
this.config(options);

/**
Expand Down Expand Up @@ -514,6 +516,20 @@ export default class Server {
}
}

/**
Checks whether or not the server can handle a verb / url
@param {string} verb The HTTP verb
@param {string} path The URL or path to check
@return {boolean} Can the server handle this verb / url
@public
*/
canHandle(verb, url) {
return this.requestHandler.canHandle(verb, url);
}

/**
* Determines if the current environment is the testing environment.
*
Expand Down Expand Up @@ -1057,18 +1073,18 @@ export default class Server {
let timing =
options.timing !== undefined ? options.timing : () => this.timing;

if (this.pretender) {
return this.pretender[verb](
fullPath,
request => {
return routeHandler.handle(request).then(mirageResponse => {
let [code, headers, response] = mirageResponse;
let handler = request => {
return routeHandler.handle(request).then(mirageResponse => {
let [code, headers, response] = mirageResponse;

return [code, headers, this._serialize(response)];
});
},
timing
);
return [code, headers, this._serialize(response)];
});
};

this.requestHandler.register(verb, fullPath, handler);

if (this.pretender) {
return this.pretender[verb](fullPath, handler, timing);
}
}

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@
"lodash.uniq": "^4.5.0",
"lodash.uniqby": "^4.7.0",
"lodash.values": "^4.3.0",
"pretender": "3.3.1"
"pretender": "3.3.1",
"route-recognizer": "^0.3.4",
"url-parse": "^1.4.7"
},
"devDependencies": {
"@babel/core": "^7.5.5",
Expand Down
20 changes: 19 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4358,6 +4358,11 @@ qs@~6.5.2:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==

querystringify@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==

react-is@^16.12.0:
version "16.12.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c"
Expand Down Expand Up @@ -4529,6 +4534,11 @@ require-main-filename@^2.0.0:
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==

requires-port@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=

resolve-cwd@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
Expand Down Expand Up @@ -4674,7 +4684,7 @@ rollup@^1.17.0:
"@types/node" "*"
acorn "^7.1.0"

route-recognizer@^0.3.3:
route-recognizer@^0.3.3, route-recognizer@^0.3.4:
version "0.3.4"
resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.4.tgz#39ab1ffbce1c59e6d2bdca416f0932611e4f3ca3"
integrity sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g==
Expand Down Expand Up @@ -5340,6 +5350,14 @@ urix@^0.1.0:
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=

url-parse@^1.4.7:
version "1.4.7"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
dependencies:
querystringify "^2.1.1"
requires-port "^1.0.0"

use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
Expand Down

0 comments on commit 6eeb644

Please sign in to comment.