0
# Middleware
1
2
The middleware system provides composable functions for server functions to handle validation, authentication, logging, and other cross-cutting concerns. Middleware can be chained together and applied to server functions for enhanced functionality.
3
4
## Capabilities
5
6
### Create Middleware
7
8
Creates middleware that can be applied to server functions for request/response processing.
9
10
```typescript { .api }
11
/**
12
* Creates middleware with optional configuration
13
* @param options - Configuration options including middleware type
14
* @returns CreateMiddlewareResult for chaining additional configuration
15
*/
16
function createMiddleware<TType extends MiddlewareType>(
17
options?: { type?: TType }
18
): CreateMiddlewareResult<{}, TType>;
19
20
interface CreateMiddlewareResult<TRegister, TType> {
21
/** Add middleware function to the chain */
22
middleware<T>(middleware: T): CreateMiddlewareResult<TRegister & T, TType>;
23
24
/** Add input validation to the middleware */
25
inputValidator<T>(validator: T): CreateMiddlewareResult<TRegister & T, TType>;
26
27
/** Add client-side processing */
28
client<T>(client: T): CreateMiddlewareResult<TRegister & T, TType>;
29
30
/** Add server-side processing */
31
server<T>(server: T): CreateMiddlewareResult<TRegister & T, TType>;
32
}
33
34
type MiddlewareType = 'request' | 'function';
35
```
36
37
**Usage Examples:**
38
39
```typescript
40
import { createMiddleware, createServerFn } from "@tanstack/react-start";
41
42
// Authentication middleware
43
const authMiddleware = createMiddleware()
44
.server(async (input, { request }) => {
45
const token = request.headers.get('Authorization');
46
if (!token) throw new Error('Unauthorized');
47
48
const user = await verifyToken(token);
49
return { ...input, user };
50
});
51
52
// Validation middleware
53
const validateUserInput = createMiddleware()
54
.inputValidator((data: unknown) => {
55
if (!data || typeof data !== 'object') {
56
throw new Error('Invalid input');
57
}
58
return data as { name: string; email: string };
59
});
60
61
// Apply middleware to server function
62
const createUser = createServerFn({ method: 'POST' })
63
.middleware(authMiddleware)
64
.middleware(validateUserInput)
65
.handler(async ({ name, email, user }) => {
66
// Handler receives validated input + auth context
67
return await db.user.create({
68
data: { name, email, createdBy: user.id }
69
});
70
});
71
```
72
73
### Function Middleware
74
75
Middleware specifically designed for server functions with type-safe parameter passing.
76
77
```typescript { .api }
78
interface FunctionMiddleware<TInput, TOutput, TContext = {}> {
79
(input: TInput, context: FunctionMiddlewareContext<TContext>):
80
Promise<TOutput> | TOutput;
81
}
82
83
interface FunctionMiddlewareContext<T = {}> {
84
/** Current request object */
85
request: Request;
86
/** Response headers */
87
headers: Headers;
88
/** Additional context data */
89
context: T;
90
/** Continue to next middleware */
91
next: () => Promise<any>;
92
}
93
94
interface FunctionMiddlewareOptions<
95
TRegister,
96
TResponse,
97
TMiddlewares,
98
TInputValidator,
99
THandler
100
> {
101
middleware?: TMiddlewares;
102
inputValidator?: TInputValidator;
103
handler?: THandler;
104
}
105
```
106
107
**Usage Examples:**
108
109
```typescript
110
import { createMiddleware } from "@tanstack/react-start";
111
112
// Logging middleware
113
const logMiddleware = createMiddleware()
114
.server(async (input, { request, next }) => {
115
console.log(`[${new Date().toISOString()}] ${request.method} ${request.url}`);
116
const start = Date.now();
117
118
const result = await next();
119
120
console.log(`Request completed in ${Date.now() - start}ms`);
121
return result;
122
});
123
124
// Rate limiting middleware
125
const rateLimitMiddleware = createMiddleware()
126
.server(async (input, { request, next }) => {
127
const ip = request.headers.get('x-forwarded-for') || 'unknown';
128
const key = `rate-limit:${ip}`;
129
130
const requests = await redis.incr(key);
131
if (requests === 1) {
132
await redis.expire(key, 60); // 1 minute window
133
}
134
135
if (requests > 100) {
136
throw new Error('Rate limit exceeded');
137
}
138
139
return await next();
140
});
141
```
142
143
### Request Middleware
144
145
Middleware that operates at the request level before server functions are invoked.
146
147
```typescript { .api }
148
interface RequestMiddleware<TContext = {}> {
149
(request: Request, context: RequestMiddlewareContext<TContext>):
150
Promise<Response | void> | Response | void;
151
}
152
153
interface RequestMiddlewareContext<T = {}> {
154
/** Additional context data */
155
context: T;
156
/** Continue to next middleware */
157
next: () => Promise<Response>;
158
}
159
160
interface RequestMiddlewareOptions<
161
TRegister,
162
TMiddlewares,
163
TServer
164
> {
165
type: 'request';
166
middleware?: TMiddlewares;
167
server?: TServer;
168
}
169
```
170
171
### Middleware Utilities
172
173
Helper functions for working with middleware chains and validation.
174
175
```typescript { .api }
176
/**
177
* Flattens nested middleware arrays into a single array
178
* @param middlewares - Array of middleware to flatten
179
* @returns Flattened middleware array
180
*/
181
function flattenMiddlewares(
182
middlewares: AnyFunctionMiddleware[]
183
): AnyFunctionMiddleware[];
184
185
/**
186
* Executes a middleware chain
187
* @param middlewares - The middleware chain to execute
188
* @param context - The execution context
189
* @returns Result of middleware execution
190
*/
191
function executeMiddleware<T>(
192
middlewares: AnyFunctionMiddleware[],
193
context: T
194
): Promise<T>;
195
196
/**
197
* Apply middleware to a function
198
* @param middleware - The middleware to apply
199
* @param fn - The function to wrap with middleware
200
* @returns Enhanced function with middleware
201
*/
202
function applyMiddleware<T>(
203
middleware: AnyFunctionMiddleware[],
204
fn: T
205
): T;
206
207
/**
208
* Execute validation logic
209
* @param validator - The validator to execute
210
* @param input - The input to validate
211
* @returns Validated output
212
*/
213
function execValidator<T, U>(
214
validator: Validator<T, U>,
215
input: T
216
): U;
217
```
218
219
### Middleware Composition
220
221
```typescript { .api }
222
interface IntersectAllValidatorInputs<T extends ReadonlyArray<any>> {
223
// Type helper for combining validator inputs
224
}
225
226
interface IntersectAllValidatorOutputs<T extends ReadonlyArray<any>> {
227
// Type helper for combining validator outputs
228
}
229
230
interface AssignAllMiddleware<T extends ReadonlyArray<any>> {
231
// Type helper for combining middleware types
232
}
233
```
234
235
## Advanced Patterns
236
237
### Conditional Middleware
238
239
```typescript
240
import { createMiddleware } from "@tanstack/react-start";
241
242
const conditionalAuth = createMiddleware()
243
.server(async (input, { request, next }) => {
244
const publicPaths = ['/health', '/api/public'];
245
const path = new URL(request.url).pathname;
246
247
if (publicPaths.includes(path)) {
248
return await next();
249
}
250
251
// Apply authentication for protected paths
252
const token = request.headers.get('Authorization');
253
if (!token) throw new Error('Authentication required');
254
255
const user = await verifyToken(token);
256
return { ...input, user };
257
});
258
```
259
260
### Error Handling Middleware
261
262
```typescript
263
import { createMiddleware } from "@tanstack/react-start";
264
265
const errorHandlerMiddleware = createMiddleware()
266
.server(async (input, { next }) => {
267
try {
268
return await next();
269
} catch (error) {
270
console.error('Server function error:', error);
271
272
if (error.message === 'Unauthorized') {
273
throw new Response('Unauthorized', { status: 401 });
274
}
275
276
throw new Response('Internal Server Error', { status: 500 });
277
}
278
});
279
```
280
281
## Types
282
283
```typescript { .api }
284
// Middleware type definitions
285
type MiddlewareType = 'request' | 'function';
286
287
interface AnyFunctionMiddleware {
288
type: 'function';
289
middleware: (...args: any[]) => any;
290
}
291
292
interface AnyRequestMiddleware {
293
type: 'request';
294
middleware: (request: Request, context: any) => any;
295
}
296
297
// Function middleware types
298
interface FunctionMiddlewareWithTypes<
299
TRegister,
300
TResponse,
301
TMiddlewares,
302
TInputValidator,
303
THandler
304
> {
305
middleware?: TMiddlewares;
306
inputValidator?: TInputValidator;
307
handler?: THandler;
308
}
309
310
interface FunctionMiddlewareValidator<T, U> {
311
(input: T): U;
312
}
313
314
interface FunctionMiddlewareServer<TInput, TOutput> {
315
(input: TInput, context: ServerFnCtx): Promise<TOutput> | TOutput;
316
}
317
318
interface FunctionMiddlewareClient<TInput, TOutput> {
319
(input: TInput): Promise<TOutput> | TOutput;
320
}
321
322
// Request middleware types
323
interface RequestMiddlewareWithTypes<
324
TRegister,
325
TMiddlewares,
326
TServer
327
> {
328
type: 'request';
329
middleware?: TMiddlewares;
330
server?: TServer;
331
}
332
333
interface RequestServerFn<T> {
334
(request: Request, context: T): Promise<Response | void> | Response | void;
335
}
336
337
// Middleware context types
338
interface FunctionMiddlewareAfterMiddleware<T> {
339
context: T;
340
next: () => Promise<any>;
341
}
342
343
interface RequestMiddlewareAfterMiddleware<T> {
344
context: T;
345
next: () => Promise<Response>;
346
}
347
348
// Validator types
349
interface Validator<TInput, TOutput> {
350
(input: TInput): TOutput;
351
}
352
353
// Context assignment helpers
354
interface AssignAllClientContextBeforeNext<T extends ReadonlyArray<any>> {
355
// Type helper for client context assignment
356
}
357
358
interface FunctionClientResultWithContext<T, U> {
359
result: T;
360
context: U;
361
}
362
363
interface FunctionServerResultWithContext<T, U> {
364
result: T;
365
context: U;
366
}
367
```