Skip to content
Open
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
6 changes: 3 additions & 3 deletions src/content/docs/en/guides/middleware.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export const onRequest = async (context, next) => {

## Middleware types

You can import and use the utility function `defineMiddleware()` to take advantage of type safety:
You can import and use the utility function [`defineMiddleware()`](/en/reference/modules/astro-middleware/#definemiddleware) to take advantage of type safety:

```ts
// src/middleware.ts
Expand Down Expand Up @@ -205,7 +205,7 @@ validation response

<p><Since v="4.13.0" /></p>

The `APIContext` exposes a method called `rewrite()` which works the same way as [Astro.rewrite](/en/guides/routing/#rewrites).
The `APIContext` exposes a method called [`rewrite()`](/en/reference/api-reference/#rewrite) which works the same way as [Astro.rewrite](/en/guides/routing/#rewrites).

Use `context.rewrite()` inside middleware to display a different page's content without [redirecting](/en/guides/routing/#dynamic-redirects) your visitor to a new page. This will trigger a new rendering phase, causing any middleware to be re-executed.

Expand Down Expand Up @@ -249,7 +249,7 @@ export function onRequest (context, next) {

The `next()` function accepts the same payload of [the `Astro.rewrite()` function](/en/reference/api-reference/#rewrite). The location of the rewrite path can be provided as a string, URL, or `Request`.

When you have multiple middleware functions chained via [sequence()](#chaining-middleware), submitting a path to `next()` will rewrite the `Request` in place and the middleware will not execute again. The next middleware function in the chain will receive the new `Request` with its updated `context`:
When you have multiple middleware functions chained via [sequence()](#chaining-middleware), submitting a path to `next()` will rewrite the `Request` in place and the middleware will not execute again. The next middleware function in the chain will receive the new `Request` with its updated `context`.

Calling `next()` with this signature will create a new `Request` object using the old `ctx.request`. This means that trying to consume `Request.body`, either before or after this rewrite, will throw a runtime error. This error is often raised with [Astro Actions that use HTML forms](/en/guides/actions/#call-actions-from-an-html-form-action). In these cases, we recommend handling rewrites from your Astro templates using `Astro.rewrite()` instead of using middleware.

Expand Down
135 changes: 115 additions & 20 deletions src/content/docs/en/reference/modules/astro-middleware.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,30 @@ Middleware allows you to intercept requests and responses and inject behaviors d

## Imports from `astro:middleware`

The following helpers are imported from the virtual middleware module:

```js
import {
sequence,
createContext,
trySerializeLocals,
defineMiddleware,
} from 'astro:middleware';
sequence,
} from 'astro:middleware';
```

### `defineMiddleware()`

You can import and use the utility function `defineMiddleware()` to take advantage of type safety:
<p>

**Type:** `(fn: MiddlewareHandler) => MiddlewareHandler`
</p>

A function for defining a middleware function with type safety. When you use this utility, the [`context`](#context) and [`next()`](#next) arguments are automatically typed, and you get a Typescript error when you try to return a [value not supported](#onrequest) in your middleware.

```ts
// src/middleware.ts
```ts title="src/middleware.ts"
import { defineMiddleware } from "astro:middleware";

// `context` and `next` are automatically typed
// `context` is typed with `APIContext` and `next` is typed with `MiddlewareNext`
export const onRequest = defineMiddleware((context, next) => {

/* your middleware logic */
});
```

Expand All @@ -51,25 +55,46 @@ A function that accepts middleware functions as arguments, and will execute them
```js title="src/middleware.js"
import { sequence } from "astro:middleware";

async function validation(_, next) {...}
async function auth(_, next) {...}
async function greeting(_, next) {...}
async function validation(context, next) {/* ... */}
async function auth(context, next) {/* ... */}
async function greeting(context, next) {/* ... */}

export const onRequest = sequence(validation, auth, greeting);
```

## Imports from `astro/middleware`

The following helpers can be imported from the regular middleware module when you build an [Astro Integration](/en/reference/integrations-reference/):

```js
import {
createContext,
defineMiddleware,
sequence,
trySerializeLocals,
} from "astro/middleware";
```

### `createContext()`

<p>

**Type:** `(context: CreateContext) => APIContext`<br />
**Type:** <code>(context: <a href="#createcontext-1">CreateContext</a>) => <a href="/en/reference/api-reference/">APIContext</a></code><br />
<Since v="2.8.0" />
</p>

A low-level API to create an [`APIContext`](/en/reference/api-reference/)to be passed to an Astro middleware `onRequest()` function.
A low-level API to create an [`APIContext`](/en/reference/api-reference/)to be passed to an Astro middleware [`onRequest()` function](#onrequest).

This function can be used by integrations/adapters to programmatically execute the Astro middleware.

### `defineMiddleware()`

See [`defineMiddleware()`](#definemiddleware) from `astro:middleware`.

### `sequence()`

See [`sequence()`](#sequence) from `astro:middleware`.

### `trySerializeLocals()`

<p>
Expand All @@ -80,6 +105,76 @@ This function can be used by integrations/adapters to programmatically execute t

A low-level API that takes in any value and tries to return a serialized version (a string) of it. If the value cannot be serialized, the function will throw a runtime error.

## `astro/middleware` types

The following types are imported from the regular middleware module:

```js
import type {
CreateContext,
} from "astro/middleware";
```

### `CreateContext`

<p>

**Type:** `{ request: Request; params?: Params; userDefinedLocales?: string[]; defaultLocale: string; locals: App.Locals; }`<br />
<Since v="2.8.0" />
</p>

An object to [create a context](#createcontext) to be passed to an Astro middleware. This contains the following properties:

#### `request`

<p>

**Type:** `Request`
</p>

The incoming [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) object.

#### `params`

<p>

**Type:** `Params`
</p>

An object containing the optional parameters to be passed to [`Astro.params`](/en/reference/api-reference/#params).

#### `userDefinedLocales`

<p>

**Type:** `string[]`<br />
<Since v="3.5.0" />
</p>

A list of supported locales defined in the [user's `i18n` configuration](/en/reference/configuration-reference/#i18nlocales).

#### `defaultLocale`

<p>

**Type:** `string`<br />
<Since v="4.16.0" />
</p>

The default locale defined in the [user's `i18n` configuration](/en/reference/configuration-reference/#i18ndefaultlocale).

#### `locals`

<p>

**Type:** `App.Locals`<br />
<Since v="5.0.0" />
</p>

An object for storing arbitrary information from a middleware, accessible to the user via [`Astro.locals`](/en/reference/api-reference/#locals).

<ReadMore>Learn more about [storing data in `locals`](/en/guides/middleware/#storing-data-in-contextlocals) with example usage.</ReadMore>

## Middleware exports

When defining your project’s middleware in `src/middleware.js`, export the following user-defined functions:
Expand All @@ -88,14 +183,14 @@ When defining your project’s middleware in `src/middleware.js`, export the fol

**Type:** `(context: APIContext, next: MiddlewareNext) => Promise<Response> | Response | Promise<void> | void`

A required exported function from `src/middleware.js` that will be called before rendering every page or API route. It receives two arguments: [context](#context) and [next()](#next). `onRequest()` must return a `Response`: either directly, or by calling `next()`.
A required exported function from `src/middleware.js` that will be called before rendering every page or API route. It receives two arguments: [`context`](#context) and [`next()`](#next). `onRequest()` must return a `Response`: either directly, or by calling `next()`.

```js title="src/middleware.js"
export function onRequest (context, next) {
// intercept response data from a request
// optionally, transform the response
// return a Response directly, or the result of calling `next()`
return next();
// intercept response data from a request
// optionally, transform the response
// return a Response directly, or the result of calling `next()`
return next();
};
```

Expand All @@ -121,4 +216,4 @@ The first argument of `onRequest()` is a context object. It mirrors many of the

The second argument of `onRequest()` is a function that calls all the subsequent middleware in the chain and returns a `Response`. For example, other middleware could modify the HTML body of a response and awaiting the result of `next()` would allow your middleware to respond to those changes.

Since Astro v4.13.0, `next()` accepts an optional URL path parameter in the form of a string, `URL`, or `Request` to [rewrite](/en/guides/routing/#rewrites) the current request without retriggering a new rendering phase.
Since Astro v4.13.0, `next()` accepts an optional URL path parameter in the form of a string, `URL`, or `Request` to [rewrite](/en/guides/routing/#rewrites) the current request without retriggering a new rendering phase.