Skip to content

Commit

Permalink
update: remove experimental wording about middleware (#3331)
Browse files Browse the repository at this point in the history
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
  • Loading branch information
ematipico and sarah11918 authored Jun 6, 2023
1 parent 527bd31 commit 3c5bdc8
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 37 deletions.
127 changes: 90 additions & 37 deletions src/content/docs/en/guides/middleware.mdx
Original file line number Diff line number Diff line change
@@ -1,70 +1,124 @@
---
title: Middleware (Experimental)
description: Learn how to enable experimental middleware support in Astro.
title: Middleware
description: Learn how to use middleware in Astro.
i18nReady: false
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro'

**Middleware** is enabled in Astro behind an experimental flag. Middleware allows you to intercept requests and responses and inject behaviors dynamically every time a page or endpoint is about to be rendered.
**Middleware** allows you to intercept requests and responses and inject behaviors dynamically every time a page or endpoint is about to be rendered.

This also allows you to set and share request-specific information across endpoints and pages by mutating a `locals` object that is available in all Astro components and API endpoints

Middleware is available in both SSG and SSR Astro projects.

:::caution
Middleware is an experimental Astro feature introduced in v2.4. This API is subject to change before it is marked as stable.
:::
## Basic Usage

## Enabling Middleware in your Project
1. Create `src/middleware.js|ts` (Alternatively, you can create `src/middleware/index.js|ts`.)

Enabling middleware should not cause any breaking changes in your project, but you may encounter errors or bugs as you use experimental middleware features.
2. Inside this file, export an [`onRequest()`](#onrequest) function. This must not be a default export.

Please refer to the [middleware RFC](https://github.com/withastro/roadmap/pull/555) for more information.
```js title="src/middleware.js"
export function onRequest ({ locals, request }, next) {
// intercept response data from a request
// optionally, transform the response by modifying `locals`
locals.title = "New title"

// return a Response or the result of calling `next()`
return next()
};
```

There are two ways to enable experimental middleware support: update `astro.config.mjs` manually or use the CLI.
3. Inside any `.astro` file, access response data using `Astro.locals`

To enable middleware manually, add the following lines to your `astro.config.mjs` configuration file:
```astro title="src/components/Component.astro"
---
const data = Astro.locals;
---
<h1>{data.title}</h1>
<p>This {data.property} is from middleware.</p>
```

### Middleware types

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

```js title="astro.config.mjs" ins={4-6}
import { defineConfig } from 'astro/config';

export default defineConfig({
experimental: {
middleware: true
}
});
```ts tilte="src/middleware.ts"
import { defineMiddleware } from "astro/middleware";

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

})
```

To enable using the CLI instead, you can use the `--experimental-middleware` flag.
Instead, if you're using JsDoc to take advantage of type safety, you can use `MiddlewareRequestHandler`:

## Basic Usage
```js tilte="src/middleware.js"

1. Create `src/middleware.js|ts` (Alternatively, you can create `src/middleware/index.js|ts`.)
/**
* @type import("astro").MiddlewareResponseHandler
*/
// `context` and `next` are automatically typed
export const onRequest = (context, next) => {

2. Inside this file, export an [`onRequest()`](#onrequest) function. This must not be a default export.
}

```js title="src/middleware.js"
export function onRequest ({ locals, request }, next) {
// intercept response data from a request
// optionally, transform the response by modifying `locals`
locals.title = "New title"

// return a Response or the result of calling `next()`
return next()
};
```

3. Inside any `.astro` file, access response data using `Astro.locals`
To type the information inside `Astro.locals`, which gives you autocompletion inside `.astro` files and middleware code, declare a global namespace in the `env.d.ts` file:

```ts title="src/env.d.ts"
/// <reference types="astro/client" />
declare global {
namespace App {
interface Locals {
user: {
name: string
},
welcomeTitle: () => String,
orders: Map<string, object>
}
}
}
```

```astro title="src/components/Component.astro"
Then, inside middleware file, we can take advantage of autocompletion and type safety.

You can store any type of data inside `Astro.locals`: strings, numbers, and even complex data types such as functions, and maps.


```js title="src/middleware.js"
export function onRequest ({ locals, request }, next) {
// intercept response data from a request
// optionally, transform the response by modifying `locals`
locals.user.name = "John Wick"
locals.welcomeTitle = () => {
return "Welcome back " + locals.user.name
}

// return a Response or the result of calling `next()`
return next()
};
```
Then you can use this information inside any `.astro` file.

```astro title="src/pages/Orders.astro"
---
const data = Astro.locals;
const title = Astro.locals.welcomeTitle();
const orders = Array.from(Astro.locals.orders.entries());
---
<h1>{data.title}</h1>
<h1>{title}</h1>
<p>This {data.property} is from middleware.</p>
<ul>
{orders.map(order => {
return <li>{// do something with each order}</li>
})}
</ul>
```


### Example: redacting sensitive information

The example below uses middleware to replace "PRIVATE INFO" with the word "REDACTED" to allow you to render modified HTML on your page:
Expand All @@ -81,7 +135,6 @@ export const onRequest = async (context, next) => {
});
}
```
For more usage examples, please see [the middleware RFC proposal](https://github.com/withastro/roadmap/blob/rfc/stage-3-middleware/proposals/0032-middleware-api.md#middleware-workflow-and-examples)

### Chaining middleware

Expand Down
35 changes: 35 additions & 0 deletions src/content/docs/en/reference/api-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,24 @@ And would render HTML like this:
</ul>
```


### `Astro.locals`

`Astro.locals` is an object containing any values from the [`context.locals`](#contextlocals) object from a middleware. Use this to access data returned by middleware in your `.astro` files.

```astro title="src/pages/Orders.astro"
---
const title = Astro.locals.welcomeTitle();
const orders = Array.from(Astro.locals.orders.entries());
---
<h1>{title}</h1>
<ul>
{orders.map(order => {
return <li>{// do something with each order}</li>
})}
</ul>
```

## Endpoint Context

[Endpoint functions](/en/core-concepts/endpoints/) receive a context object as the first parameter. It mirrors many of the `Astro` global properties.
Expand Down Expand Up @@ -570,6 +588,23 @@ export function get({ redirect }: APIContext) {

See also: [`Astro.redirect()`](#astroredirect)

### `context.locals`

`context.locals` is an object available **only in middleware functions**. You can use this object to store arbitrary
information during the lifecycle of a request.


```ts title="src/middleware.ts"
import type { MiddlewareResponseHandler } from 'astro';

export const onRequest: MiddlewareResponseHandler = ({ locals }, next) => {
locals.title = "New Title"
return next();
}
```

See also: [`Astro.locals`](#astrolocals)

## `getStaticPaths()`

If a page uses dynamic params in the filename, that component will need to export a `getStaticPaths()` function.
Expand Down

0 comments on commit 3c5bdc8

Please sign in to comment.