diff --git a/src/lib/router.ts b/src/lib/router.ts index 7bf99d49e..0fbb0fc08 100644 --- a/src/lib/router.ts +++ b/src/lib/router.ts @@ -63,6 +63,7 @@ const allRoutes: RouteDefinition[] = [ { label: "Factories", name: "factories" }, { label: "Fixtures", name: "fixtures" }, { label: "Serializers", name: "serializers" }, + { label: "Middleware", name: "middleware" }, ], }, { diff --git a/src/routes/docs/getting-started/introduction.mdx b/src/routes/docs/getting-started/introduction.mdx index fdfb38517..4bfaa5c33 100644 --- a/src/routes/docs/getting-started/introduction.mdx +++ b/src/routes/docs/getting-started/introduction.mdx @@ -95,7 +95,7 @@ In addition to intercepting HTTP requests, Mirage provides a mock database and h Mirage borrows concepts from typical server-side frameworks like -- **routes** to handle HTTP requests +- **routes** and **middleware** to handle HTTP requests - a **database** and **models** for storing data and defining relationships - **factories** and **fixtures** for stubbing data, and - **serializers** for formatting HTTP responses diff --git a/src/routes/docs/main-concepts/fixtures.mdx b/src/routes/docs/main-concepts/fixtures.mdx index 84551c2d3..10bf6320b 100644 --- a/src/routes/docs/main-concepts/fixtures.mdx +++ b/src/routes/docs/main-concepts/fixtures.mdx @@ -297,4 +297,4 @@ Still, fixtures can be quite useful in certain situations, so they're a good too --- -Next, we'll wrap up this section of the guides by learning about Serializers, which let us customize how Mirage formats our data before sending it back in response to our app. +Next up, we'll learn about Serializers which let us customize how Mirage formats our data before sending it back in response to our app. diff --git a/src/routes/docs/main-concepts/middleware.mdx b/src/routes/docs/main-concepts/middleware.mdx new file mode 100644 index 000000000..1775ac335 --- /dev/null +++ b/src/routes/docs/main-concepts/middleware.mdx @@ -0,0 +1,98 @@ +# Middleware + +Middleware lets you write code which runs before and after route handlers, and middleware can be shared by many route handlers, too. + +For example, you can write middleware to check requests on their way to the route handlers: + +```js +function requireContentType(value) { + return (schema, request, next) => { + if (request.requestHeaders['Content-Type'] !== value) { + return new Response(400, {}, `Content-Type must be "${value}"`); + } + return next(); + } +} +``` + +...or you can write middleware to modify the responses on their way back to the client: + +```js +function addOurSpecialResponseHeader() { + return (schema, request, next) => { + const [status, headers, payload] = next().toRackResponse(); + return new Response(status, { 'special-header': '1', ...headers }, payload); + } +} +``` + +## Adding middleware to route handlers + +When you define your route handlers you can specify which middleware to use. Each set of middleware applies to the subsequent route definitions. + +```js +routes() { + this.middleware = [ + requireContentType('application/json'), + ]; + + this.get("/movies", /*...*/); + this.get("/movies/:id", /*...*/); + + this.middleware = [ + requireContentType('application/xml'), + addOurSpecialResponseHeader(), + ]; + + this.get("/movies.xml", /*...*/); + this.get("/movies/:id.xml", /*...*/); +} +``` + +## More example middleware + +Catching errors + +```js +function catchError(klass, handler) { + return (schema, request, next) => { + try { + return next(); + } catch(e) { + if (e instanceof klass) { + return handler(e); + } + throw e; + } + } +} + +routes() { + this.middleware = [ + catchError(Error, handleInternalServerError), + catchError(InvalidQueryError, handleBadRequest), + ]; +``` + +Randomizing failures + +```js +function random500() { + return (schema, request, next) => { + return Math.random() < 0.2 ? new Response(500, {}, 'internal error') : next(); + } +} + +routes() { + this.middleware = [ + random500(), + ] +``` + +--- + +Middleware is a simple mechanism which isn't tied to any particular use case, so you can stretch your imagination when using it. + +--- + +Now that we've covered all of Mirage's main concepts, we're ready to see how we can use Mirage to effectively test our JavaScript application. diff --git a/src/routes/docs/main-concepts/serializers.mdx b/src/routes/docs/main-concepts/serializers.mdx index 25b0d0368..f4fb0f53e 100644 --- a/src/routes/docs/main-concepts/serializers.mdx +++ b/src/routes/docs/main-concepts/serializers.mdx @@ -315,4 +315,4 @@ Be sure to check out the API docs to learn about all the hooks available to cust --- -Now that we've covered all of Mirage's main concepts, we're ready to see how we can use Mirage to effectively test our JavaScript application. +Next, we'll wrap up this section of the guides by learning about Middleware, a powerful way to share functionality across route handlers. \ No newline at end of file