Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: changes for next release #11708

Merged
merged 4 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 185 additions & 40 deletions www/apps/book/app/learn/fundamentals/api-routes/middlewares/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,20 @@ As Medusa's server is based on Express, you can use any [Express middleware](htt

</Note>

### Middleware Types

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).

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 Middleware?
## How to Create a Global Middleware?

Middlewares 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.
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:

Expand Down Expand Up @@ -57,13 +66,69 @@ 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 middleware functions.
- `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
```

In the example above, you define a middleware that logs the message `Received a request!` whenever a request is sent to an API route path starting with `/custom`.
2. Send a request to any API route starting with `/custom`.
3. See the following message in the terminal:

```bash
Received a request!
```

---

## Test the Middleware
## 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:

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"
import {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
defineMiddlewares,
} 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()
},
],
},
],
})
```

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.

### Test the Route Middleware

To test the middleware:

Expand All @@ -73,7 +138,7 @@ To test the middleware:
npm run dev
```

2. Send a request to any API route starting with `/custom`.
2. Send a `POST` request to any API route starting with `/custom`.
3. See the following message in the terminal:

```bash
Expand Down Expand Up @@ -141,15 +206,13 @@ This applies a middleware to the routes defined in the file `src/api/custom/[id]

---

## Restrict HTTP Methods

Restrict which HTTP methods the middleware is applied to using the `method` property of the middleware route object.
## Request URLs with Trailing Backslashes

For example:
A middleware whose `matcher` pattern doesn't end with a backslash won't be applied for requests to URLs with a trailing backslash.

export const highlights = [["12", "method", "Apply the middleware only on `POST` requests"]]
For example, consider you have the following middleware:

```ts title="src/api/middlewares.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
```ts title="src/api/middlewares.ts" collapsibleLines="1-7" expandMoreLabel="Show Imports"
import {
MedusaNextFunction,
MedusaRequest,
Expand All @@ -160,48 +223,126 @@ import {
export default defineMiddlewares({
routes: [
{
matcher: "/custom*",
method: ["POST", "PUT"],
matcher: "/custom",
middlewares: [
// ...
(
req: MedusaRequest,
res: MedusaResponse,
next: MedusaNextFunction
) => {
console.log("Received a request!")

next()
},
],
},
],
})
```

`method`'s value is one or more HTTP methods to apply the middleware to.
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.

This example applies the middleware only when a `POST` or `PUT` request is sent to an API route path starting with `/custom`.
In general, avoid adding trailing backslashes when sending requests to API routes.

---

## Request URLs with Trailing Backslashes
## Middlewares and Route Ordering

A middleware whose `matcher` pattern doesn't end with a backslash won't be applied for requests to URLs with a trailing backslash.
<Note>

For example, consider you have the following middleware:
The ordering explained in this section was added in [Medusa v2.6](https://github.com/medusajs/medusa/releases/tag/v2.6)

```ts collapsibleLines="1-7" expandMoreLabel="Show Imports"
import {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
defineMiddlewares,
} from "@medusajs/framework/http"
</Note>

The Medusa application registers middlewares and API route handlers in the following order:

1. Global middlewares in the following order:
1. Global middleware defined in the Medusa's core.
2. Global middleware defined in the plugins (in the order the plugins are registered in).
3. Global middleware you define in the application.
2. Route middlewares in the following order:
1. Route middleware defined in the Medusa's core.
2. Route middleware defined in the plugins (in the order the plugins are registered in).
3. Route middleware you define in the application.
3. API routes in the following order:
1. API routes defined in the Medusa's core.
2. API routes defined in the plugins (in the order the plugins are registered in).
3. API routes you define in the application.

### Middlewares Sorting

On top of the previous ordering, Medusa sorts global and route middlewares based on their matcher pattern in the following order:

1. Wildcard matchers. For example, `/custom*`.
2. Regex matchers. For example, `/custom/(products|collections)`.
3. Static matchers without parameters. For example, `/custom`.
4. Static matchers with parameters. For example, `/custom/:id`.

For example, if you have the following middlewares:

```ts title="src/api/middlewares.ts"
export default defineMiddlewares({
routes: [
{
matcher: "/custom/:id",
middlewares: [/* ... */],
},
{
matcher: "/custom",
middlewares: [
(
req: MedusaRequest,
res: MedusaResponse,
next: MedusaNextFunction
) => {
console.log("Received a request!")
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:

1. Global middleware `/custom`.
2. Global middleware `/custom/:id`.

And the route middlewares are sorted into the following order before they're registered:

1. Route middleware `/custom*`.
2. Route middleware `/custom/:id`.

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()
},
],
Expand All @@ -210,16 +351,20 @@ export default defineMiddlewares({
})
```

If you send a request to `http://localhost:9000/custom`, the middleware will run.
When you send a request to `/custom` route, the following messages are logged in the terminal:

However, if you send a request to `http://localhost:9000/custom/`, the middleware won't run.
```bash
Global middleware
Route middleware
Hello from custom! # message logged from API route handler
```

In general, avoid adding trailing backslashes when sending requests to API routes.
The global middleware runs first, then the route middleware, and finally the route handler, assuming that it logs the message `Hello from custom!`.

---

## Middlewares Precedence in Registration
## Overriding Middlewares

The Medusa application registers your middlewares first, then registers middlewares defined in Medusa's core.
A middleware can not override an existing middleware. Instead, middlewares are added to the end of the middleware stack.

So, if you add a middleware for a route defined in the core, it might get overridden by the core middleware. For example, if you add a middleware to change authentication of admin routes, the authentication middleware defined in the core will still run, leading to your middleware not being effective.
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.
2 changes: 1 addition & 1 deletion www/apps/book/generated/edit-dates.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const generatedEditDates = {
"app/learn/fundamentals/admin/tips/page.mdx": "2025-02-24T09:52:06.901Z",
"app/learn/fundamentals/api-routes/cors/page.mdx": "2024-12-09T13:04:04.357Z",
"app/learn/fundamentals/admin/ui-routes/page.mdx": "2025-02-24T09:35:11.752Z",
"app/learn/fundamentals/api-routes/middlewares/page.mdx": "2025-02-12T17:05:20.708Z",
"app/learn/fundamentals/api-routes/middlewares/page.mdx": "2025-03-04T10:16:15.029Z",
"app/learn/fundamentals/modules/isolation/page.mdx": "2024-12-09T11:02:38.087Z",
"app/learn/fundamentals/data-models/configure-properties/page.mdx": "2024-10-21T13:30:21.368Z",
"app/learn/fundamentals/data-models/index/page.mdx": "2024-10-21T13:30:21.368Z",
Expand Down
Loading
Loading