www/apps/book/app/learn/fundamentals/api-routes/middlewares/page.mdx
import { Table, CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: ${pageNumber} Middlewares,
}
In this chapter, you’ll learn about middlewares and how to create them.
A middleware is a function executed when a request is sent to an API Route. It's executed before the route handler function.
Middlewares are used to guard API routes, parse request content types other than application/json, manipulate request data, and more.
As Medusa's server is based on Express, you can use any Express middleware.
</Note>There are two types of middlewares:
<Table> <Table.Header> <Table.Row> <Table.HeaderCell> Type </Table.HeaderCell> <Table.HeaderCell> Description </Table.HeaderCell> <Table.HeaderCell> Example </Table.HeaderCell> </Table.Row> </Table.Header> <Table.Body> <Table.Row> <Table.Cell> Global Middleware </Table.Cell> <Table.Cell> A middleware that applies to all routes matching a specified pattern. </Table.Cell> <Table.Cell> `/custom*` applies to all routes starting with `/custom` </Table.Cell> </Table.Row> <Table.Row> <Table.Cell> Route Middleware </Table.Cell> <Table.Cell> A middleware that applies to routes matching a specified pattern and HTTP method(s). </Table.Cell> <Table.Cell> A middleware that applies to all `POST` requests to routes starting with `/custom`. </Table.Cell> </Table.Row> </Table.Body> </Table>These middlewares generally have the same definition and usage, but they differ in the routes they apply to. You'll learn how to create both types in the following sections.
Middlewares of all types are defined in the special file src/api/middlewares.ts. Use the defineMiddlewares function from the Medusa Framework to define the middlewares, and export its value.
For example:
<CodeTabs group="middleware-type"> <CodeTab label="Global Middleware" value="global-middleware">import {
defineMiddlewares,
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
} from "@medusajs/framework/http"
export default defineMiddlewares({
routes: [
{
matcher: "/custom*",
middlewares: [
(
req: MedusaRequest,
res: MedusaResponse,
next: MedusaNextFunction
) => {
console.log("Received a request!")
next()
},
],
},
],
})
export const highlights = [["12", "method", "Apply the middleware only on POST requests"]]
import {
defineMiddlewares,
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
} from "@medusajs/framework/http"
export default defineMiddlewares({
routes: [
{
matcher: "/custom*",
method: ["POST", "PUT"],
middlewares: [
(
req: MedusaRequest,
res: MedusaResponse,
next: MedusaNextFunction
) => {
console.log("Received a request!")
next()
},
],
},
],
})
The defineMiddlewares function accepts a middleware configurations object that has the property routes. routes's value is an array of middleware route objects, each having the following properties:
matcher: a string or regular expression indicating the API route path to apply the middleware on. The regular expression must be compatible with path-to-regexp.middlewares: An array of global and route middleware functions.method: (optional) By default, a middleware is applied on all HTTP methods for a route. You can specify one or more HTTP methods to apply the middleware to in this option, making it a route middleware.To test the middleware:
npm run dev
/custom. If you specified an HTTP method in the method property, make sure to use that method.Received a request!
If the middleware didn't run, make sure you've correctly created the middleware at src/api/middlewares.ts (with correct spelling). This is a common mistake that can lead to the middleware not being applied, resulting in unexpected behavior.
Middlewares are useful for:
application/json.The middleware function accepts three parameters:
MedusaRequest.MedusaResponse.MedusaNextFunction that executes the next middleware in the stack.You must call the next function in the middleware. Otherwise, other middlewares and the API route handler won’t execute.
For example:
import {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
defineMiddlewares,
} from "@medusajs/framework/http"
export default defineMiddlewares({
routes: [
{
matcher: "/custom*",
middlewares: [
(
req: MedusaRequest,
res: MedusaResponse,
next: MedusaNextFunction
) => {
console.log("Received a request!", req.body)
next()
},
],
},
],
})
This middleware logs the request body to the terminal, then calls the next function to execute the next middleware in the stack.
To indicate a path parameter in a middleware's matcher pattern, use the format :{param-name}.
A middleware applied on a route with path parameters is a route middleware.
</Note>For example:
export const pathParamHighlights = [["11", ":id", "Indicates that the API route accepts an id path parameter."]]
import {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
defineMiddlewares,
} from "@medusajs/framework/http"
export default defineMiddlewares({
routes: [
{
matcher: "/custom/:id",
middlewares: [
// ...
],
},
],
})
This applies a middleware to the routes defined in the file src/api/custom/[id]/route.ts.
A middleware whose matcher pattern doesn't end with a backslash won't be applied for requests to URLs with a trailing backslash.
For example, consider you have the following middleware:
import {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
defineMiddlewares,
} from "@medusajs/framework/http"
export default defineMiddlewares({
routes: [
{
matcher: "/custom",
middlewares: [
(
req: MedusaRequest,
res: MedusaResponse,
next: MedusaNextFunction
) => {
console.log("Received a request!")
next()
},
],
},
],
})
If you send a request to http://localhost:9000/custom, the middleware will run.
However, if you send a request to http://localhost:9000/custom/, the middleware won't run.
In general, avoid adding trailing backslashes when sending requests to API routes.
The information explained in this section is applicable starting from Medusa v2.6.
</Note>The Medusa application registers middlewares and API route handlers in the following order, stacking them on top of each other:
Then, when a request is sent to an API route, the stack is executed in order: global middlewares are executed first, then the route middlewares, and finally the route handlers.
For example, consider you have the following middlewares:
export default defineMiddlewares({
routes: [
{
matcher: "/custom",
middlewares: [
(req, res, next) => {
console.log("Global middleware")
next()
},
],
},
{
matcher: "/custom",
method: ["GET"],
middlewares: [
(req, res, next) => {
console.log("Route middleware")
next()
},
],
},
],
})
When you send a request to /custom route, the following messages are logged in the terminal:
Global middleware
Route middleware
Hello from custom! # message logged from API route handler
The global middleware runs first, then the route middleware, and finally the route handler, assuming that it logs the message Hello from custom!.
On top of the previous ordering, Medusa sorts global and route middlewares based on their matcher pattern in the following order:
/custom*./custom/(products|collections)./custom./custom/:id.For example, if you have the following middlewares:
export default defineMiddlewares({
routes: [
{
matcher: "/custom/:id",
middlewares: [/* ... */],
},
{
matcher: "/custom",
middlewares: [/* ... */],
},
{
matcher: "/custom*",
method: ["GET"],
middlewares: [/* ... */],
},
{
matcher: "/custom/:id",
method: ["GET"],
middlewares: [/* ... */],
},
],
})
The global middlewares are sorted into the following order before they're registered:
/custom./custom/:id.And the route middlewares are sorted into the following order before they're registered:
/custom*./custom/:id.Then, the middlwares are registered in the order mentioned earlier, with global middlewares first, then the route middlewares.
A middleware can not override an existing middleware. Instead, middlewares are added to the end of the middleware stack.
For example, if you define a custom validation middleware, such as validateAndTransformBody, on an existing route, then both the original and the custom validation middleware will run.
Similarly, if you add an authenticate middleware to an existing route, both the original and the custom authentication middleware will run. So, you can't override the original authentication middleware.
If you need to change the middlewares applied to a route, you can create a custom API route that executes the same functionality as the original route, but with the middlewares you want.
Learn more in the Override API Routes chapter.