docs: updates to middlewares and protected API routes + new chapter (#12419)

This commit is contained in:
Shahed Nasser
2025-05-09 12:06:34 +03:00
committed by GitHub
parent 7c7e44d9fe
commit 28285f309a
10 changed files with 24651 additions and 24032 deletions
@@ -1,3 +1,5 @@
import { Table, CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `${pageNumber} Middlewares`,
}
@@ -12,6 +14,8 @@ A middleware is a function executed when a request is sent to an API Route. It's
Middlewares are used to guard API routes, parse request content types other than `application/json`, manipulate request data, and more.
![Diagram showcasing how a middleware is executed when a request is sent to an API route.](https://res.cloudinary.com/dza7lstvk/image/upload/v1746775148/Medusa%20Book/middleware-overview_wc2ws5.jpg)
<Note title="Tip">
As Medusa's server is based on Express, you can use any [Express middleware](https://expressjs.com/en/resources/middleware.html).
@@ -22,19 +26,59 @@ As Medusa's server is based on Express, you can use any [Express middleware](htt
There are two types of middlewares:
1. Global Middleware: A middleware that applies to all routes matching a specified pattern.
2. Route Middleware: A middleware that applies to routes matching a specified pattern and HTTP method(s).
<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.
---
## How to Create a Global Middleware?
## How to Create a Middleware?
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">
```ts title="src/api/middlewares.ts"
import {
defineMiddlewares,
@@ -63,46 +107,17 @@ export default defineMiddlewares({
})
```
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](https://github.com/pillarjs/path-to-regexp).
- `middlewares`: An array of global and route middleware functions.
In the example above, you define a global middleware that logs the message `Received a request!` whenever a request is sent to an API route path starting with `/custom`.
### Test the Global Middleware
To test the middleware:
1. Start the application:
```bash npm2yarn
npm run dev
```
2. Send a request to any API route starting with `/custom`.
3. See the following message in the terminal:
```bash
Received a request!
```
---
## How to Create a Route Middleware?
In the previous section, you learned how to create a global middleware. You define the route middleware in the same way in `src/api/middlewares.ts`, but you specify an additional property `method` in the middleware route object. Its value is one or more HTTP methods to apply the middleware to.
For example:
</CodeTab>
<CodeTab label="Route Middleware" value="route-middleware">
export const highlights = [["12", "method", "Apply the middleware only on `POST` requests"]]
```ts title="src/api/middlewares.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
```ts title="src/api/middlewares.ts" highlights={highlights}
import {
defineMiddlewares,
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
defineMiddlewares,
} from "@medusajs/framework/http"
export default defineMiddlewares({
@@ -126,9 +141,16 @@ export default defineMiddlewares({
})
```
This example applies the middleware only when a `POST` or `PUT` request is sent to an API route path starting with `/custom`, changing the middleware from a global middleware to a route middleware.
</CodeTab>
</CodeTabs>
### Test the Route Middleware
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](https://github.com/pillarjs/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.
### Test the Middleware
To test the middleware:
@@ -138,7 +160,7 @@ To test the middleware:
npm run dev
```
2. Send a `POST` request to any API route starting with `/custom`.
2. Send a request to any API route starting with `/custom`. If you specified an HTTP method in the `method` property, make sure to use that method.
3. See the following message in the terminal:
```bash
@@ -149,12 +171,12 @@ Received a request!
## When to Use Middlewares
<Note type="success" title="Use middlewares when">
Middlewares are useful for:
- You want to protect API routes by a custom condition.
- You're modifying the request body.
</Note>
- [Protecting API routes](../protected-routes/page.mdx) to ensure that only authenticated users can access them.
- [Validating](../validation/page.mdx) request query and body parameters.
- [Parsing](../parse-body/page.mdx) request content types other than `application/json`.
- [Applying CORS](../cors/page.mdx) configurations to custom API routes.
---
@@ -172,12 +194,50 @@ You must call the `next` function in the middleware. Otherwise, other middleware
</Note>
For example:
```ts title="src/api/middlewares.ts"
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.
---
## Middleware for Routes with Path Parameters
To indicate a path parameter in a middleware's `matcher` pattern, use the format `:{param-name}`.
<Note title="Tip">
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."]]
@@ -248,15 +308,19 @@ In general, avoid adding trailing backslashes when sending requests to API route
---
## Middlewares and Route Ordering
## How Are Middlewares Ordered and Applied?
<Note>
The ordering explained in this section was added in [Medusa v2.6](https://github.com/medusajs/medusa/releases/tag/v2.6)
The information explained in this section is applicable starting from [Medusa v2.6](https://github.com/medusajs/medusa/releases/tag/v2.6).
</Note>
The Medusa application registers middlewares and API route handlers in the following order:
### Middleware and Routes Execution Order
The Medusa application registers middlewares and API route handlers in the following order, stacking them on top of each other:
![Diagram showcasing the order in which middlewares and route handlers are registered.](https://res.cloudinary.com/dza7lstvk/image/upload/v1746776911/Medusa%20Book/middleware-registration-overview_spc02f.jpg)
1. Global middlewares in the following order:
1. Global middleware defined in the Medusa's core.
@@ -271,6 +335,48 @@ The Medusa application registers middlewares and API route handlers in the follo
2. API routes defined in the plugins (in the order the plugins are registered in).
3. API routes you define in the application.
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.
![Diagram showcasing the order in which middlewares and route handlers are executed when a request is sent to an API route.](https://res.cloudinary.com/dza7lstvk/image/upload/v1746776172/Medusa%20Book/middleware-order-overview_h7kzfl.jpg)
For example, consider you have the following middlewares:
```ts title="src/api/middlewares.ts"
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:
```bash
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!`.
### Middlewares Sorting
On top of the previous ordering, Medusa sorts global and route middlewares based on their matcher pattern in the following order:
@@ -317,50 +423,10 @@ And the route middlewares are sorted into the following order before they're reg
1. Route middleware `/custom*`.
2. Route middleware `/custom/:id`.
![Diagram showcasing the order in which middlewares are sorted before being registered.](https://res.cloudinary.com/dza7lstvk/image/upload/v1746777297/Medusa%20Book/middleware-registration-sorting_oyfqhw.jpg)
Then, the middlwares are registered in the order mentioned earlier, with global middlewares first, then the route middlewares.
### Middlewares and Route Execution Order
When a request is sent to an API route, the global middlewares are executed first, then the route middlewares, and finally the route handler.
For example, consider you have the following middlewares:
```ts title="src/api/middlewares.ts"
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:
```bash
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!`.
---
## Overriding Middlewares
@@ -368,3 +434,11 @@ The global middleware runs first, then the route middleware, and finally the rou
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](../protected-routes/page.mdx#protect-custom-api-routes) middleware to an existing route, both the original and the custom authentication middleware will run. So, you can't override the original authentication middleware.
### Alternative Solution to Overriding Middlewares
If you need to change the middlewares applied to a route, you can create a custom [API route](../page.mdx) that executes the same functionality as the original route, but with the middlewares you want.
Learn more in the [Override API Routes](../override/page.mdx) chapter.