0
# Request/Response Utilities
1
2
TanStack Start provides utilities for accessing HTTP request information within server functions. These utilities give you access to request data, headers, and client information during server-side execution.
3
4
## Capabilities
5
6
### Request Information Functions
7
8
Access information about the current HTTP request.
9
10
```typescript { .api }
11
/**
12
* Get the current request object
13
* @returns Current HTTP request
14
*/
15
function getRequest(): Request;
16
17
/**
18
* Get all request headers
19
* @returns Object containing all request headers
20
*/
21
function getRequestHeaders(): Record<string, string>;
22
23
/**
24
* Get a specific request header value
25
* @param name - Header name to retrieve
26
* @returns Header value or undefined
27
*/
28
function getRequestHeader(name: string): string | undefined;
29
30
/**
31
* Get the client IP address from the request
32
* @param options - Options for IP detection
33
* @returns Client IP address or undefined
34
*/
35
function getRequestIP(options?: { ipHeader?: string }): string | undefined;
36
```
37
38
**Usage Examples:**
39
40
```typescript
41
import {
42
getRequest,
43
getRequestHeaders,
44
getRequestHeader,
45
getRequestIP
46
} from "@tanstack/react-start";
47
48
// Access request information in a server function
49
const getUserInfo = createServerFn()
50
.handler(async () => {
51
const request = getRequest();
52
const headers = getRequestHeaders();
53
const userAgent = getRequestHeader("user-agent");
54
const clientIP = getRequestIP({ ipHeader: "x-forwarded-for" });
55
56
return {
57
method: request.method,
58
url: request.url,
59
userAgent,
60
clientIP,
61
headers
62
};
63
});
64
65
// Using request data for authentication
66
const authenticatedAction = createServerFn()
67
.handler(async () => {
68
const authHeader = getRequestHeader("authorization");
69
70
if (!authHeader || !authHeader.startsWith("Bearer ")) {
71
throw new Error("Authentication required");
72
}
73
74
const token = authHeader.substring(7);
75
// Verify token...
76
77
return { authenticated: true };
78
});
79
80
// Getting client information
81
const trackUserAction = createServerFn()
82
.handler(async (action: string) => {
83
const request = getRequest();
84
const userAgent = getRequestHeader("user-agent");
85
const clientIP = getRequestIP();
86
const referer = getRequestHeader("referer");
87
88
// Log the action with client information
89
console.log({
90
action,
91
userAgent,
92
clientIP,
93
referer,
94
timestamp: new Date().toISOString()
95
});
96
97
return { success: true };
98
});
99
```
100
101
### Response Utilities
102
103
Utilities for creating and manipulating HTTP responses.
104
105
```typescript { .api }
106
/**
107
* Create a JSON response with proper headers
108
* @param data - Data to serialize as JSON
109
* @param options - Response options
110
* @returns JSON response object
111
*/
112
function json<T>(
113
data: T,
114
options?: { status?: number; headers?: HeadersInit }
115
): JsonResponse;
116
117
/**
118
* Merge multiple header objects into one
119
* @param headers - Header objects to merge
120
* @returns Merged headers object
121
*/
122
function mergeHeaders(...headers: HeadersInit[]): Headers;
123
```
124
125
**Usage Examples:**
126
127
```typescript
128
import { json, mergeHeaders } from "@tanstack/react-start";
129
130
// Create JSON responses
131
const getUsers = createServerFn()
132
.handler(async () => {
133
const users = await db.user.findMany();
134
135
return json(users, {
136
status: 200,
137
headers: { "Cache-Control": "max-age=300" }
138
});
139
});
140
141
// Create responses with merged headers
142
const createUser = createServerFn()
143
.handler(async (userData) => {
144
const user = await db.user.create({ data: userData });
145
146
const responseHeaders = mergeHeaders(
147
{ "Content-Type": "application/json" },
148
{ "X-User-ID": user.id },
149
{ "Cache-Control": "no-cache" }
150
);
151
152
return json(user, {
153
status: 201,
154
headers: responseHeaders
155
});
156
});
157
158
// Error responses
159
const deleteUser = createServerFn()
160
.handler(async (userId: string) => {
161
const user = await db.user.findUnique({ where: { id: userId } });
162
163
if (!user) {
164
return json(
165
{ error: "User not found" },
166
{ status: 404 }
167
);
168
}
169
170
await db.user.delete({ where: { id: userId } });
171
172
return json({ success: true });
173
});
174
```
175
176
## Advanced Usage Patterns
177
178
### Request Body Processing
179
180
```typescript
181
import { getRequest } from "@tanstack/react-start";
182
183
const processFormData = createServerFn()
184
.handler(async () => {
185
const request = getRequest();
186
187
if (request.method !== "POST") {
188
return json({ error: "Method not allowed" }, { status: 405 });
189
}
190
191
const contentType = getRequestHeader("content-type");
192
193
if (contentType?.includes("application/json")) {
194
const jsonData = await request.json();
195
return json({ received: jsonData });
196
} else if (contentType?.includes("multipart/form-data")) {
197
const formData = await request.formData();
198
const data = Object.fromEntries(formData);
199
return json({ received: data });
200
}
201
202
return json({ error: "Unsupported content type" }, { status: 400 });
203
});
204
```
205
206
### CORS Handling
207
208
```typescript
209
import { mergeHeaders, json } from "@tanstack/react-start";
210
211
const corsEnabledApi = createServerFn()
212
.handler(async () => {
213
const origin = getRequestHeader("origin");
214
const allowedOrigins = ["https://example.com", "https://app.example.com"];
215
216
const corsHeaders = allowedOrigins.includes(origin)
217
? {
218
"Access-Control-Allow-Origin": origin,
219
"Access-Control-Allow-Credentials": "true"
220
}
221
: {};
222
223
const responseHeaders = mergeHeaders(
224
{ "Content-Type": "application/json" },
225
corsHeaders
226
);
227
228
return json(
229
{ message: "API response" },
230
{ headers: responseHeaders }
231
);
232
});
233
```
234
235
### Request Validation
236
237
```typescript
238
const validateApiKey = createServerFn()
239
.handler(async () => {
240
const apiKey = getRequestHeader("x-api-key");
241
const userAgent = getRequestHeader("user-agent");
242
const clientIP = getRequestIP();
243
244
if (!apiKey) {
245
return json(
246
{ error: "API key required" },
247
{ status: 401 }
248
);
249
}
250
251
// Rate limiting based on IP
252
const requestCount = await redis.get(`requests:${clientIP}`);
253
if (requestCount && parseInt(requestCount) > 100) {
254
return json(
255
{ error: "Rate limit exceeded" },
256
{ status: 429 }
257
);
258
}
259
260
// Validate API key
261
const isValid = await validateAPIKey(apiKey);
262
if (!isValid) {
263
return json(
264
{ error: "Invalid API key" },
265
{ status: 403 }
266
);
267
}
268
269
// Increment request count
270
await redis.incr(`requests:${clientIP}`);
271
await redis.expire(`requests:${clientIP}`, 3600);
272
273
return json({ success: true });
274
});
275
```
276
277
## Types
278
279
```typescript { .api }
280
// JSON response type
281
interface JsonResponse {
282
json(): any;
283
status: number;
284
headers: Headers;
285
ok: boolean;
286
statusText: string;
287
}
288
289
// Request IP options
290
interface RequestIPOptions {
291
ipHeader?: string;
292
}
293
```