0
# Request and Response
1
2
Connection objects for accessing request data and generating responses. The Request object provides access to HTTP request data including headers, body, query parameters, and path parameters. Response objects handle returning different content types and status codes.
3
4
## Capabilities
5
6
### Request Object
7
8
The Request object provides access to all aspects of an incoming HTTP request through a rich API for headers, body parsing, parameters, and more.
9
10
```python { .api }
11
class Request(ASGIConnection):
12
def __init__(self, scope: Scope, receive: Receive = empty_receive):
13
"""
14
Initialize a Request object.
15
16
Parameters:
17
- scope: ASGI scope dictionary
18
- receive: ASGI receive callable
19
"""
20
21
# Body parsing methods
22
async def body(self) -> bytes:
23
"""Get the raw request body as bytes."""
24
25
async def json(self) -> Any:
26
"""Parse request body as JSON."""
27
28
async def form(self) -> dict[str, str | list[str]]:
29
"""Parse request body as form data."""
30
31
async def msgpack(self) -> Any:
32
"""Parse request body as MessagePack."""
33
34
async def stream(self) -> AsyncIterator[bytes]:
35
"""Stream the request body in chunks."""
36
37
# Parameter access
38
@property
39
def query_params(self) -> MultiDict[str, str]:
40
"""Get query parameters as a MultiDict."""
41
42
@property
43
def path_params(self) -> dict[str, Any]:
44
"""Get path parameters with type conversion."""
45
46
# Headers and cookies
47
@property
48
def headers(self) -> Headers:
49
"""Get request headers."""
50
51
@property
52
def cookies(self) -> dict[str, str]:
53
"""Get request cookies."""
54
55
# Request metadata
56
@property
57
def method(self) -> Method:
58
"""Get HTTP method."""
59
60
@property
61
def url(self) -> URL:
62
"""Get request URL."""
63
64
@property
65
def content_type(self) -> tuple[str, dict[str, str]]:
66
"""Get content type and parameters."""
67
68
@property
69
def client(self) -> Address | None:
70
"""Get client address."""
71
72
@property
73
def auth(self) -> Any:
74
"""Get authentication information."""
75
76
@property
77
def user(self) -> Any:
78
"""Get authenticated user."""
79
80
@property
81
def state(self) -> State:
82
"""Get request state."""
83
84
@property
85
def session(self) -> dict[str, Any]:
86
"""Get session data."""
87
88
# Request matching
89
def url_for(self, name: str, **path_parameters: Any) -> str:
90
"""Generate URL for named route."""
91
92
def url_for_static_asset(self, name: str, file_path: str) -> str:
93
"""Generate URL for static asset."""
94
```
95
96
### Response Objects
97
98
Response objects handle different content types and response configurations.
99
100
```python { .api }
101
class Response:
102
def __init__(
103
self,
104
content: Any = None,
105
*,
106
status_code: int = 200,
107
headers: ResponseHeaders | None = None,
108
media_type: MediaType | str | None = None,
109
background: BackgroundTask | BackgroundTasks | None = None,
110
cookies: Sequence[Cookie] | None = None,
111
encoding: str = "utf-8",
112
):
113
"""
114
Create a Response object.
115
116
Parameters:
117
- content: Response content (automatically serialized)
118
- status_code: HTTP status code
119
- headers: Response headers
120
- media_type: Content media type
121
- background: Background task(s) to execute after response
122
- cookies: Response cookies
123
- encoding: Content encoding
124
"""
125
126
@property
127
def content(self) -> bytes:
128
"""Get response content as bytes."""
129
130
def set_header(self, key: str, value: str) -> None:
131
"""Set a response header."""
132
133
def set_cookie(
134
self,
135
key: str,
136
value: str | None = None,
137
*,
138
max_age: int | None = None,
139
expires: int | datetime | None = None,
140
path: str = "/",
141
domain: str | None = None,
142
secure: bool = False,
143
httponly: bool = False,
144
samesite: Literal["lax", "strict", "none"] = "lax",
145
) -> None:
146
"""Set a response cookie."""
147
148
def delete_cookie(
149
self,
150
key: str,
151
path: str = "/",
152
domain: str | None = None,
153
) -> None:
154
"""Delete a cookie."""
155
```
156
157
### File Response
158
159
Response for serving files with proper headers and streaming support.
160
161
```python { .api }
162
class File(Response):
163
def __init__(
164
self,
165
path: str | Path,
166
*,
167
filename: str | None = None,
168
stat_result: os.stat_result | None = None,
169
chunk_size: int = 1024 * 1024,
170
content_disposition_type: Literal["attachment", "inline"] = "attachment",
171
etag: ETag | None = None,
172
**kwargs: Any,
173
):
174
"""
175
Create a file response.
176
177
Parameters:
178
- path: Path to the file
179
- filename: Override filename in Content-Disposition header
180
- stat_result: Pre-computed file stat result
181
- chunk_size: Size of chunks for streaming
182
- content_disposition_type: Content disposition type
183
- etag: ETag configuration
184
"""
185
```
186
187
### Streaming Response
188
189
Response for streaming data to the client.
190
191
```python { .api }
192
class Stream(Response):
193
def __init__(
194
self,
195
iterator: Iterator[str | bytes] | AsyncIterator[str | bytes],
196
*,
197
media_type: MediaType | str = MediaType.TEXT,
198
**kwargs: Any,
199
):
200
"""
201
Create a streaming response.
202
203
Parameters:
204
- iterator: Iterator yielding response chunks
205
- media_type: Content media type
206
"""
207
```
208
209
### Redirect Response
210
211
Response for HTTP redirects.
212
213
```python { .api }
214
class Redirect(Response):
215
def __init__(
216
self,
217
path: str,
218
*,
219
status_code: int = HTTP_302_FOUND,
220
**kwargs: Any,
221
):
222
"""
223
Create a redirect response.
224
225
Parameters:
226
- path: Redirect target URL
227
- status_code: HTTP redirect status code
228
"""
229
```
230
231
### Template Response
232
233
Response for rendered templates.
234
235
```python { .api }
236
class Template(Response):
237
def __init__(
238
self,
239
name: str,
240
context: dict[str, Any] | None = None,
241
*,
242
**kwargs: Any,
243
):
244
"""
245
Create a template response.
246
247
Parameters:
248
- name: Template name
249
- context: Template context variables
250
"""
251
```
252
253
### Server-Sent Events
254
255
Response for server-sent events streaming.
256
257
```python { .api }
258
class ServerSentEvent(Response):
259
def __init__(
260
self,
261
iterator: Iterator[ServerSentEventMessage] | AsyncIterator[ServerSentEventMessage],
262
*,
263
**kwargs: Any,
264
):
265
"""
266
Create a server-sent events response.
267
268
Parameters:
269
- iterator: Iterator yielding SSE messages
270
"""
271
272
class ServerSentEventMessage:
273
def __init__(
274
self,
275
data: str | bytes | dict | list,
276
*,
277
event: str | None = None,
278
id: str | None = None,
279
retry: int | None = None,
280
comment: str | None = None,
281
):
282
"""
283
Create an SSE message.
284
285
Parameters:
286
- data: Message data
287
- event: Event type
288
- id: Message ID
289
- retry: Retry interval in milliseconds
290
- comment: Comment text
291
"""
292
```
293
294
### Data Structures
295
296
Core data structures used in requests and responses.
297
298
```python { .api }
299
class Headers(CaseInsensitiveDict[str]):
300
"""Case-insensitive HTTP headers dictionary."""
301
302
def __init__(self, headers: Mapping[str, str] | RawHeaders | None = None):
303
"""Initialize headers from mapping or raw headers."""
304
305
def add(self, key: str, value: str) -> None:
306
"""Add a header value (allows duplicates)."""
307
308
def get_list(self, key: str) -> list[str]:
309
"""Get all values for a header as a list."""
310
311
class MultiDict(dict[str, str]):
312
"""Dictionary supporting multiple values per key."""
313
314
def getlist(self, key: str) -> list[str]:
315
"""Get all values for a key as a list."""
316
317
def add(self, key: str, value: str) -> None:
318
"""Add a value for a key."""
319
320
class Cookie:
321
def __init__(
322
self,
323
key: str,
324
value: str | None = None,
325
*,
326
max_age: int | None = None,
327
expires: int | datetime | None = None,
328
path: str = "/",
329
domain: str | None = None,
330
secure: bool = False,
331
httponly: bool = False,
332
samesite: Literal["lax", "strict", "none"] = "lax",
333
):
334
"""Create a cookie."""
335
336
class URL:
337
def __init__(self, url: str = ""):
338
"""Parse a URL string."""
339
340
@property
341
def scheme(self) -> str:
342
"""Get URL scheme."""
343
344
@property
345
def hostname(self) -> str | None:
346
"""Get hostname."""
347
348
@property
349
def port(self) -> int | None:
350
"""Get port number."""
351
352
@property
353
def path(self) -> str:
354
"""Get URL path."""
355
356
@property
357
def query(self) -> str:
358
"""Get query string."""
359
360
@property
361
def fragment(self) -> str:
362
"""Get URL fragment."""
363
364
def replace(self, **kwargs: Any) -> URL:
365
"""Create a new URL with replaced components."""
366
```
367
368
## Usage Examples
369
370
### Request Data Access
371
372
```python
373
from litestar import get, post, Request
374
from litestar.exceptions import ValidationException
375
376
@get("/info")
377
async def request_info(request: Request) -> dict:
378
return {
379
"method": request.method,
380
"url": str(request.url),
381
"headers": dict(request.headers),
382
"query_params": dict(request.query_params),
383
"client": request.client.host if request.client else None,
384
}
385
386
@get("/search")
387
async def search(request: Request) -> dict:
388
query = request.query_params.get("q", "")
389
limit = int(request.query_params.get("limit", "10"))
390
391
return {
392
"query": query,
393
"limit": limit,
394
"results": [] # Search results would go here
395
}
396
397
@post("/data")
398
async def handle_data(request: Request) -> dict:
399
content_type = request.headers.get("content-type", "")
400
401
if "application/json" in content_type:
402
data = await request.json()
403
elif "application/x-www-form-urlencoded" in content_type:
404
data = await request.form()
405
else:
406
raise ValidationException("Unsupported content type")
407
408
return {"received": data}
409
```
410
411
### Custom Response Types
412
413
```python
414
from litestar import get
415
from litestar.response import Response, File, Stream, Redirect
416
from litestar.status_codes import HTTP_201_CREATED
417
import json
418
419
@get("/custom")
420
async def custom_response() -> Response:
421
data = {"message": "Custom response"}
422
return Response(
423
content=json.dumps(data),
424
status_code=HTTP_201_CREATED,
425
headers={"X-Custom-Header": "value"},
426
media_type="application/json"
427
)
428
429
@get("/download/{filename:str}")
430
async def download_file(filename: str) -> File:
431
return File(
432
path=f"/uploads/{filename}",
433
filename=filename,
434
content_disposition_type="attachment"
435
)
436
437
@get("/stream-data")
438
async def stream_data() -> Stream:
439
async def generate_data():
440
for i in range(100):
441
yield f"chunk {i}\n"
442
443
return Stream(
444
iterator=generate_data(),
445
media_type="text/plain"
446
)
447
448
@get("/redirect-to-docs")
449
async def redirect_to_docs() -> Redirect:
450
return Redirect("https://docs.litestar.dev")
451
```
452
453
### Cookie Handling
454
455
```python
456
from litestar import get, post, Request, Response
457
458
@post("/login")
459
async def login(request: Request) -> Response:
460
# Authenticate user (simplified)
461
user_data = await request.json()
462
463
response = Response({"status": "logged in"})
464
response.set_cookie(
465
"session_id",
466
"abc123",
467
max_age=3600, # 1 hour
468
httponly=True,
469
secure=True,
470
samesite="strict"
471
)
472
return response
473
474
@get("/profile")
475
async def get_profile(request: Request) -> dict:
476
session_id = request.cookies.get("session_id")
477
if not session_id:
478
return {"error": "Not authenticated"}
479
480
return {"user": "alice", "session": session_id}
481
482
@post("/logout")
483
async def logout() -> Response:
484
response = Response({"status": "logged out"})
485
response.delete_cookie("session_id")
486
return response
487
```
488
489
### Server-Sent Events
490
491
```python
492
from litestar import get
493
from litestar.response import ServerSentEvent, ServerSentEventMessage
494
import asyncio
495
496
@get("/events")
497
async def event_stream() -> ServerSentEvent:
498
async def generate_events():
499
counter = 0
500
while True:
501
yield ServerSentEventMessage(
502
data={"timestamp": time.time(), "counter": counter},
503
event="update",
504
id=str(counter)
505
)
506
counter += 1
507
await asyncio.sleep(1)
508
509
return ServerSentEvent(generate_events())
510
```
511
512
### File Upload Handling
513
514
```python
515
from litestar import post, Request
516
from litestar.datastructures import UploadFile
517
518
@post("/upload")
519
async def upload_file(request: Request) -> dict:
520
form_data = await request.form()
521
522
uploaded_file = form_data.get("file")
523
if isinstance(uploaded_file, UploadFile):
524
content = await uploaded_file.read()
525
return {
526
"filename": uploaded_file.filename,
527
"size": len(content),
528
"content_type": uploaded_file.content_type
529
}
530
531
return {"error": "No file uploaded"}
532
```
533
534
## Types
535
536
```python { .api }
537
# ASGI types
538
Scope = dict[str, Any]
539
Receive = Callable[[], Awaitable[Message]]
540
Send = Callable[[Message], Awaitable[None]]
541
Message = dict[str, Any]
542
543
# HTTP types
544
Method = Literal["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "TRACE"]
545
ResponseHeaders = Mapping[str, str] | Sequence[tuple[str, str]]
546
RawHeaders = list[tuple[bytes, bytes]]
547
548
# Content types
549
ContentType = tuple[str, dict[str, str]]
550
551
# Iterator types for streaming
552
SyncIterator = Iterator[str | bytes]
553
AsyncIterator = AsyncIterator[str | bytes]
554
```