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

Update middleware docs #1010

Merged
merged 64 commits into from
Feb 18, 2025
Merged
Changes from 18 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
2c024f1
draft
amirhhashemi Jan 9, 2025
7bb39d4
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 10, 2025
a88a85c
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 10, 2025
1c210d3
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 10, 2025
b94f07d
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 10, 2025
c53bca2
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 11, 2025
a013d57
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 13, 2025
3bb0e91
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 13, 2025
250e489
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 17, 2025
7a54c37
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 18, 2025
bf2058d
update
amirhhashemi Jan 12, 2025
38c21f9
update
amirhhashemi Jan 19, 2025
bb4c551
update
amirhhashemi Jan 25, 2025
f56071b
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 25, 2025
e4d6706
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 27, 2025
e9beddf
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 28, 2025
d7907b7
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 28, 2025
6c32d24
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 28, 2025
d548034
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 28, 2025
fcba8b5
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 28, 2025
d4d4a32
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 28, 2025
c348b17
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 28, 2025
082ad76
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 29, 2025
aafc73b
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 29, 2025
d82db67
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 29, 2025
e3888ee
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 29, 2025
e96d75a
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 29, 2025
d1f9dec
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 29, 2025
0ca1b5d
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 29, 2025
2f44d77
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 29, 2025
d2e6290
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 29, 2025
60d44df
fix formatting issues
amirhhashemi Jan 29, 2025
afe7ae9
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 29, 2025
b216446
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 29, 2025
7012608
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 30, 2025
616d68c
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Jan 30, 2025
656db68
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 31, 2025
7d4d5a2
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 31, 2025
4f9795d
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 31, 2025
802747e
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 31, 2025
90baec1
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 31, 2025
93d2d56
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 31, 2025
1f36ab1
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 31, 2025
fbe6d3f
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 31, 2025
a07a8a0
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 31, 2025
9685ff0
Update src/routes/solid-start/advanced/middleware.mdx
amirhhashemi Jan 31, 2025
73372b5
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 6, 2025
b768d7c
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 6, 2025
9fd7a3c
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 7, 2025
cfdd037
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 7, 2025
d673e4a
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 7, 2025
0eecf28
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 7, 2025
82e53f9
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 10, 2025
4249f84
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 13, 2025
c1bdea6
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 13, 2025
546ae6c
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 13, 2025
a22b0ea
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 13, 2025
b4e993a
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 16, 2025
feafee5
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 16, 2025
1c42e1c
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 16, 2025
0d90adf
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 18, 2025
123789a
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 18, 2025
3265790
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 18, 2025
de132c0
Merge branch 'main' into update-middleware-docs
kodiakhq[bot] Feb 18, 2025
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
291 changes: 280 additions & 11 deletions src/routes/solid-start/advanced/middleware.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,297 @@
title: "Middleware"
---

Middlewares may be included by passing file you specify in your start config.
Middleware intercepts HTTP requests and responses to perform tasks like authentication, redirection, logging, and more.
It also enables sharing request-scoped data across the application using the `event.locals` object.

```js
## Common use cases

Here are some common use cases for middleware:

- **Request and response header management:** Middleware enables adding, modifying, or removing headers to control caching (e.g., setting `Cache-Control` headers), enhance security (e.g., setting security headers like `Content-Security-Policy`), or implement custom behavior based on request characteristics.
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
- **Global data sharing:** The `event.locals` object allows storing and sharing request-scoped data between middleware and any server-side context (e.g., API routes, server-only queries/actions). This is useful for passing information like user authentication status, feature flags, or other request-related data.
- **Server-side redirects:** Middleware can redirect users based on various request properties, such as locale (e.g., redirecting users to a localized version of the site), authentication state (e.g., redirecting unauthenticated users to a login page), or custom query parameters.
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
- **Request preprocessing:** Middleware can perform lightweight preprocessing tasks, such as validating tokens (e.g., JWT validation) or normalizing paths (e.g., removing trailing slashes).
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved

## Limitations

While middleware is powerful, it's essential to understand its limitations.
Certain tasks are better handled in other parts of your application for performance, maintainability, or security reasons:
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved

- **Authorization:** Middleware does _not_ run on every request, especially during client-side navigations.
Relying on middleware for authorization would create a significant security vulnerability.
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
Authorization checks should be performed within API routes, server-only queries/actions, or other server-side utilities, as close to the data source as possible.
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
- **Heavy computation or long-running processes:** Middleware should be lightweight and execute quickly to avoid impacting performance.
CPU-intensive tasks, long-running processes, or blocking operations (like complex calculations or external API calls) should be handled by dedicated route handlers, server-side utilities, or background jobs.
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
- **Database operations:** Performing direct database queries within middleware can lead to performance bottlenecks and make your application harder to maintain.
Database interactions should be handled by server-side utilities or route handlers.
This approach allows for better management of database connections and handling of potential errors.
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved

## Basic usage

Middleware is configured by exporting a configuration object from a dedicated file (e.g., `src/middleware/index.ts`).
This object, created using the [`createMiddleware`](/solid-start/reference/server/create-middleware) function, defines when middleware functions execute throughout the request lifecycle.

```ts title="src/middleware/index.ts"
import { createMiddleware } from "@solidjs/start/middleware";

export default createMiddleware({
onRequest: (event) => {
console.log("Request received:", event.request.url);

event.locals.startTime = Date.now();
},
onBeforeResponse: (event) => {
const endTime = Date.now();
const duration = endTime - event.locals.startTime;
console.log(`Request took ${duration}ms`);
},
});
```

For SolidStart to recognize the configuration object, the file path is declared in `app.config.ts`:

```ts title="app.config.ts"
import { defineConfig } from "@solidjs/start/config";

export default defineConfig({
middleware: "./src/middleware.ts"
middleware: "src/middleware/index.ts",
});
```

Inside the middleware file, you can export a `createMiddleware` function.
## Lifecycle events

A middleware function executes at specific points in the request lifecycle, using two key events: `onRequest` and `onBeforeResponse`.

### `onRequest`

The `onRequest` event is triggered at the beginning of the request lifecycle, before the request is handled by the route handler.
This is the ideal place to:

- Store request-scoped data in `event.locals` for use in later middleware functions or route handlers.
- Set or modify request headers.
- Perform early redirects.

### `onBeforeResponse`

The `onBeforeResponse` event is triggered after a request has been processed by the route handler but before the response is sent to the client.
This is the ideal place to:

- Set or modify response headers.
- Log response metrics or perform other post-processing tasks.
- Modify the response body.

## Locals

In web applications, there's often a need to share request-specific data across different parts of the server-side code.
This data might include user authentication status, trace IDs for debugging, or client metadata (e.g., user agent, geolocation).

```tsx
The `event.locals` object provides a temporary, request-scoped storage layer to address this need.
Data stored within it is only available during the processing of a single HTTP request and is automatically cleared afterward.
`event.locals` is a plain JavaScript object and can hold any JavaScript value.
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved

Within middleware, `event.locals` can be accessed and modified directly.
Other server-side contexts must use the [`getRequestEvent`](/reference/server-utilities/get-request-event) function to access the `event.locals` object.

This example demonstrates storing user information in `event.locals`:

```ts
import { createMiddleware } from "@solidjs/start/middleware";

export default createMiddleware({
onRequest: (event) => {
event.locals.user = {
name: "John Wick",
};
event.locals.sayHello = () => {
return "Hello, " + event.locals.user.name;
};
},
});
```

This example demonstrates accessing `event.locals` within a server-only action using `getRequestEvent`:

amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
```tsx title="src/routes/index.tsx"
import { getRequestEvent } from "solid-js/web";
import { query, createAsync } from "@solidjs/router";

const getUser = query(async () => {
"use server";
const event = getRequestEvent();
return {
name: event?.locals?.user?.name,
greeting: event?.locals?.sayHello(),
};
}, "user");

export default function Page() {
const user = createAsync(() => getUser());

return (
<div>
<p>Name: {user()?.name}</p>
<button onClick={() => alert(user()?.greeting)}>Say Hello</button>
</div>
);
}
```

## Headers

Request and response headers can be accessed and modified using the `event.request.headers` and `event.response.headers` objects.
These follow the standard Web API [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) interface, exposing built-in methods for reading/updating headers.
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved

<Callout type="info" title="Note">

Headers set in `onRequest` are applied **before** the route handler processes the request, allowing downstream middleware or route handlers to override them.
Headers set in `onBeforeResponse` are applied **after** the route handler and are finalized for the client.

</Callout>

```ts
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
import { createMiddleware } from "@solidjs/start/middleware";

export default createMiddleware({
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
onRequest: [
event => {
console.log("GLOBAL", event.request.url);
}
]
onRequest: (event) => {
// Reading client metadata for later use
const userAgent = event.request.headers.get("user-agent");

// Adding custom headers to request/response
event.request.headers.set("x-custom-request-header", "hello");
event.response.headers.set("x-custom-response-header1", "hello");
},
onBeforeResponse: (event) => {
// Finalizing response headers before sending to client
event.response.headers.set("x-custom-response-header2", "hello");
},
});
```
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved

Middleware supports 2 lifecycles: `onRequest` and `onBeforeResponse`. If you return a value from middleware it will respond with that, otherwise it will run the next one in the chain.
## Cookies

HTTP cookies are accessible through the `Cookie` request header and `Set-Cookie` response header.
While these headers can be manipulated directly, [Vinxi](https://vinxi.vercel.app), the underlying server toolkit powering SolidStart, provides helpers to simplify cookie management.
See the [Vinxi Cookies documentation](https://vinxi.vercel.app/api/server/cookies.html) for more information.

```ts
import { createMiddleware } from "@solidjs/start/middleware";
import { getCookie, setCookie } from "vinxi/http";

export default createMiddleware({
onRequest: (event) => {
// Reading a cookie
const theme = getCookie(event.nativeEvent, "theme");

// Setting a secure session cookie with expiration
setCookie(event.nativeEvent, "session", "abc123", {
httpOnly: true,
secure: true,
maxAge: 60 * 60 * 24, // 1 day
});
},
});
```

## Custom responses

Returning a value from a middleware function immediately terminates the request processing pipeline and sends the returned value as the response to the client.
This means no further middleware functions or route handlers will be executed.
amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved

<Callout type="info" title="Note">

Only [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects can be returned from middleware functions.
Returning any other value will result in an error.

</Callout>

```ts
import { createMiddleware } from "@solidjs/start/middleware";

export default createMiddleware({
onRequest: () => {
return new Response("Unauthorized", { status: 401 });
},
});
```

amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
This example returns a "401 Unauthorized" response with the text "Unauthorized" as the body, preventing further execution of middleware or route handlers.

### Redirects

amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
[Solid Router](/solid-router) provides the [`redirect`](/solid-router/reference/response-helpers/redirect) helper function which simplifies creating redirect responses.

```ts
import { createMiddleware } from "@solidjs/start/middleware";
import { redirect } from "@solidjs/router";

const REDIRECT_MAP: Record<string, string> = {
"/signup": "/auth/signup",
"/login": "/auth/login",
};

export default createMiddleware({
onRequest: (event) => {
const { pathname } = new URL(event.request.url);

// Redirecting legacy routes permanently to new paths
if (pathname in REDIRECT_MAP) {
return redirect(REDIRECT_MAP[pathname], 301);
}
},
});
```

This example checks the requested path and returns a redirect response if it matches a predefined path.
The 301 status code indicates a permanent redirect.
Other redirect status codes (e.g., 302, 307) are available as needed.

### JSON responses

amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
Solid Router provides the [`json`](/solid-router/reference/response-helpers/json) helper function which simplifies sending custom JSON responses.

```ts
import { createMiddleware } from "@solidjs/start/middleware";
import { json } from "@solidjs/router";

export default createMiddleware({
onRequest: (event) => {
// Rejecting unauthorized API requests with a JSON error
const authHeader = event.request.headers.get("Authorization");
if (!authHeader) {
return json({ error: "Unauthorized" }, { status: 401 });
}
},
});
```

## Chaining middleware functions

amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
The `onRequest` and `onBeforeResponse` options in `createMiddleware` can accept either a single function or an array of middleware functions.
When an array is provided, these functions execute sequentially within the same lifecycle event.
This enables composing smaller, more-focused middleware functions, rather than handling all logic in a single, large middleware function.

```ts
import { createMiddleware } from "@solidjs/start/middleware";
import { type FetchEvent } from "@solidjs/start/server";

function middleware1(event: FetchEvent) {
event.request.headers.set("x-custom-header1", "hello-from-middleware1");
}

function middleware2(event: FetchEvent) {
event.request.headers.set("x-custom-header2", "hello-from-middleware2");
}

export default createMiddleware({
onRequest: [middleware1, middleware2],
});
```

<Callout type="tip" title="Middleware execution order">

The order of middleware functions in the array determines their execution order.
Dependent middleware functions should be placed after the middleware functions they rely on.
For example, authentication middleware should typically run before logging middleware.

amirhhashemi marked this conversation as resolved.
Show resolved Hide resolved
</Callout>
Loading