or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api-routing.mdbackground-tasks.mdcore-application.mddependency-injection.mdexception-handling.mdfile-handling.mdindex.mdparameter-declaration.mdrequest-response.mdwebsocket-support.md

request-response.mddocs/

0

# Request and Response Handling

1

2

FastAPI provides comprehensive request and response objects for accessing HTTP request data and creating custom responses. The Request object gives access to all request information, while Response classes allow fine-grained control over HTTP responses.

3

4

## Capabilities

5

6

### Request Object

7

8

Object for accessing all HTTP request information including headers, body, query parameters, and connection details.

9

10

```python { .api }

11

class Request:

12

"""

13

HTTP request object providing access to all request data.

14

15

Attributes (read-only):

16

- method: HTTP method (GET, POST, etc.)

17

- url: Complete URL object with components

18

- headers: HTTP headers as case-insensitive mapping

19

- query_params: Query parameters as mapping

20

- path_params: Path parameters extracted from URL pattern

21

- cookies: HTTP cookies as mapping

22

- client: Client connection information (host, port)

23

- session: Session data (if session middleware is enabled)

24

- state: Application state for storing data across middleware

25

"""

26

27

method: str

28

url: URL

29

headers: Headers

30

query_params: QueryParams

31

path_params: Dict[str, Any]

32

cookies: Dict[str, str]

33

client: Optional[Address]

34

session: Dict[str, Any]

35

state: State

36

37

async def body(self) -> bytes:

38

"""

39

Get raw request body as bytes.

40

41

Returns:

42

Complete request body as bytes

43

44

Note: Can only be called once per request

45

"""

46

47

async def json(self) -> Any:

48

"""

49

Parse request body as JSON.

50

51

Returns:

52

Parsed JSON data (dict, list, or primitive)

53

54

Raises:

55

JSONDecodeError: If body is not valid JSON

56

"""

57

58

async def form(self) -> FormData:

59

"""

60

Parse request body as form data.

61

62

Returns:

63

FormData object with form fields and files

64

65

Note: Handles both URL-encoded and multipart form data

66

"""

67

68

def stream(self) -> AsyncGenerator[bytes, None]:

69

"""

70

Get request body as async stream.

71

72

Returns:

73

Async generator yielding body chunks

74

75

Note: Useful for large request bodies

76

"""

77

78

def scope(self) -> Dict[str, Any]:

79

"""

80

Get ASGI scope dictionary.

81

82

Returns:

83

Complete ASGI scope with request metadata

84

"""

85

```

86

87

### Response Classes

88

89

Classes for creating HTTP responses with control over content, headers, status codes, and media types.

90

91

```python { .api }

92

class Response:

93

"""

94

Basic HTTP response class.

95

"""

96

def __init__(

97

self,

98

content: Any = None,

99

status_code: int = 200,

100

headers: Optional[Dict[str, str]] = None,

101

media_type: Optional[str] = None,

102

background: Optional[BackgroundTask] = None

103

):

104

"""

105

Create HTTP response.

106

107

Parameters:

108

- content: Response content (string, bytes, or iterable)

109

- status_code: HTTP status code

110

- headers: Additional response headers

111

- media_type: Content-Type header value

112

- background: Background task to run after response

113

"""

114

115

class JSONResponse(Response):

116

"""

117

JSON response with automatic serialization.

118

"""

119

def __init__(

120

self,

121

content: Any = None,

122

status_code: int = 200,

123

headers: Optional[Dict[str, str]] = None,

124

media_type: str = "application/json",

125

background: Optional[BackgroundTask] = None

126

):

127

"""

128

Create JSON response with automatic serialization.

129

130

Parameters:

131

- content: Python object to serialize as JSON

132

- status_code: HTTP status code

133

- headers: Additional response headers

134

- media_type: Content-Type (defaults to application/json)

135

- background: Background task to run after response

136

"""

137

138

class HTMLResponse(Response):

139

"""

140

HTML response for serving HTML content.

141

"""

142

def __init__(

143

self,

144

content: str = "",

145

status_code: int = 200,

146

headers: Optional[Dict[str, str]] = None,

147

media_type: str = "text/html",

148

background: Optional[BackgroundTask] = None

149

):

150

"""

151

Create HTML response.

152

153

Parameters:

154

- content: HTML content as string

155

- status_code: HTTP status code

156

- headers: Additional response headers

157

- media_type: Content-Type (defaults to text/html)

158

- background: Background task to run after response

159

"""

160

161

class PlainTextResponse(Response):

162

"""

163

Plain text response.

164

"""

165

def __init__(

166

self,

167

content: str = "",

168

status_code: int = 200,

169

headers: Optional[Dict[str, str]] = None,

170

media_type: str = "text/plain",

171

background: Optional[BackgroundTask] = None

172

):

173

"""

174

Create plain text response.

175

176

Parameters:

177

- content: Plain text content

178

- status_code: HTTP status code

179

- headers: Additional response headers

180

- media_type: Content-Type (defaults to text/plain)

181

- background: Background task to run after response

182

"""

183

184

class RedirectResponse(Response):

185

"""

186

HTTP redirect response.

187

"""

188

def __init__(

189

self,

190

url: Union[str, URL],

191

status_code: int = 307,

192

headers: Optional[Dict[str, str]] = None,

193

background: Optional[BackgroundTask] = None

194

):

195

"""

196

Create redirect response.

197

198

Parameters:

199

- url: Redirect target URL

200

- status_code: HTTP redirect status code (301, 302, 307, 308)

201

- headers: Additional response headers

202

- background: Background task to run after response

203

"""

204

205

class StreamingResponse(Response):

206

"""

207

Streaming response for large or generated content.

208

"""

209

def __init__(

210

self,

211

content: Union[Iterable[Union[str, bytes]], AsyncIterable[Union[str, bytes]]],

212

status_code: int = 200,

213

headers: Optional[Dict[str, str]] = None,

214

media_type: Optional[str] = None,

215

background: Optional[BackgroundTask] = None

216

):

217

"""

218

Create streaming response.

219

220

Parameters:

221

- content: Iterable or async iterable of content chunks

222

- status_code: HTTP status code

223

- headers: Additional response headers

224

- media_type: Content-Type header value

225

- background: Background task to run after response

226

"""

227

228

class FileResponse(Response):

229

"""

230

File download response.

231

"""

232

def __init__(

233

self,

234

path: Union[str, os.PathLike],

235

status_code: int = 200,

236

headers: Optional[Dict[str, str]] = None,

237

media_type: Optional[str] = None,

238

background: Optional[BackgroundTask] = None,

239

filename: Optional[str] = None,

240

stat_result: Optional[os.stat_result] = None,

241

method: Optional[str] = None

242

):

243

"""

244

Create file download response.

245

246

Parameters:

247

- path: File system path to file

248

- status_code: HTTP status code

249

- headers: Additional response headers

250

- media_type: Content-Type (automatically detected if None)

251

- background: Background task to run after response

252

- filename: Filename for Content-Disposition header

253

- stat_result: Pre-computed file stat result

254

- method: HTTP method for conditional response

255

"""

256

```

257

258

### High-Performance Response Classes

259

260

FastAPI-specific response classes optimized for performance.

261

262

```python { .api }

263

class UJSONResponse(JSONResponse):

264

"""

265

High-performance JSON response using ujson library.

266

267

Note: Requires 'ujson' package to be installed

268

Provides faster JSON serialization than standard library

269

"""

270

271

class ORJSONResponse(JSONResponse):

272

"""

273

High-performance JSON response using orjson library.

274

275

Note: Requires 'orjson' package to be installed

276

Provides fastest JSON serialization with additional features

277

"""

278

```

279

280

### Data Structure Classes

281

282

Classes for structured access to request data components.

283

284

```python { .api }

285

class Headers:

286

"""

287

Case-insensitive HTTP headers mapping.

288

289

Supports:

290

- Case-insensitive key access

291

- Multiple values per header

292

- Standard dict-like interface

293

"""

294

295

class QueryParams:

296

"""

297

URL query parameters mapping.

298

299

Supports:

300

- Multiple values per parameter

301

- Automatic type conversion

302

- Standard dict-like interface

303

"""

304

305

class FormData:

306

"""

307

Form data container for form submissions.

308

309

Supports:

310

- Form fields as key-value pairs

311

- File uploads as UploadFile objects

312

- Multiple values per field name

313

"""

314

315

class URL:

316

"""

317

URL manipulation and component access.

318

319

Attributes:

320

- scheme: URL scheme (http, https)

321

- hostname: Hostname or IP address

322

- port: Port number

323

- path: URL path

324

- query: Query string

325

- fragment: URL fragment

326

"""

327

328

class Address:

329

"""

330

Network address representation.

331

332

Attributes:

333

- host: IP address or hostname

334

- port: Port number

335

"""

336

```

337

338

## Usage Examples

339

340

### Accessing Request Information

341

342

```python

343

from fastapi import FastAPI, Request

344

from typing import Dict, Any

345

346

app = FastAPI()

347

348

@app.get("/request-info")

349

async def get_request_info(request: Request):

350

return {

351

"method": request.method,

352

"url": str(request.url),

353

"base_url": str(request.base_url),

354

"headers": dict(request.headers),

355

"query_params": dict(request.query_params),

356

"path_params": request.path_params,

357

"cookies": request.cookies,

358

"client_host": request.client.host if request.client else None,

359

"user_agent": request.headers.get("user-agent")

360

}

361

362

@app.post("/inspect-body")

363

async def inspect_body(request: Request):

364

# Access raw body

365

body = await request.body()

366

367

# Try to parse as JSON

368

try:

369

json_data = await request.json()

370

except:

371

json_data = None

372

373

return {

374

"body_length": len(body),

375

"body_preview": body[:100].decode("utf-8", errors="ignore"),

376

"json_data": json_data,

377

"content_type": request.headers.get("content-type")

378

}

379

```

380

381

### Custom Response Classes

382

383

```python

384

from fastapi import FastAPI

385

from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse, RedirectResponse

386

387

app = FastAPI()

388

389

@app.get("/html", response_class=HTMLResponse)

390

async def get_html():

391

html_content = """

392

<html>

393

<head>

394

<title>FastAPI HTML Response</title>

395

</head>

396

<body>

397

<h1>Hello HTML!</h1>

398

<p>This is an HTML response from FastAPI.</p>

399

</body>

400

</html>

401

"""

402

return html_content

403

404

@app.get("/plain-text", response_class=PlainTextResponse)

405

async def get_plain_text():

406

return "This is plain text response"

407

408

@app.get("/custom-json")

409

async def get_custom_json():

410

return JSONResponse(

411

content={"message": "Custom JSON response"},

412

status_code=201,

413

headers={"X-Custom-Header": "custom-value"}

414

)

415

416

@app.get("/redirect-example")

417

async def redirect_example():

418

return RedirectResponse(url="/new-location", status_code=302)

419

```

420

421

### Streaming Responses

422

423

```python

424

from fastapi import FastAPI

425

from fastapi.responses import StreamingResponse

426

import io

427

import json

428

import time

429

430

app = FastAPI()

431

432

@app.get("/stream-data")

433

async def stream_data():

434

def generate_data():

435

for i in range(100):

436

data = {"item": i, "timestamp": time.time()}

437

yield f"data: {json.dumps(data)}\n"

438

time.sleep(0.1) # Simulate processing delay

439

440

return StreamingResponse(

441

generate_data(),

442

media_type="text/plain",

443

headers={"X-Stream-Type": "data-stream"}

444

)

445

446

@app.get("/stream-csv")

447

async def stream_csv():

448

def generate_csv():

449

yield "id,name,value\n"

450

for i in range(1000):

451

yield f"{i},item_{i},{i*10}\n"

452

453

return StreamingResponse(

454

generate_csv(),

455

media_type="text/csv",

456

headers={"Content-Disposition": "attachment; filename=data.csv"}

457

)

458

459

@app.get("/stream-async")

460

async def stream_async():

461

async def generate_async_data():

462

for i in range(50):

463

data = f"Async chunk {i}\n"

464

yield data.encode()

465

# Simulate async operation

466

await asyncio.sleep(0.05)

467

468

return StreamingResponse(

469

generate_async_data(),

470

media_type="text/plain"

471

)

472

```

473

474

### File Responses

475

476

```python

477

from fastapi import FastAPI, HTTPException

478

from fastapi.responses import FileResponse

479

import os

480

481

app = FastAPI()

482

483

@app.get("/download/{filename}")

484

async def download_file(filename: str):

485

file_path = f"/path/to/files/{filename}"

486

487

if not os.path.exists(file_path):

488

raise HTTPException(status_code=404, detail="File not found")

489

490

return FileResponse(

491

path=file_path,

492

filename=filename,

493

media_type="application/octet-stream"

494

)

495

496

@app.get("/download-with-name/{file_id}")

497

async def download_with_custom_name(file_id: int):

498

# Look up file by ID

499

file_info = get_file_info(file_id) # Your database lookup

500

501

return FileResponse(

502

path=file_info["path"],

503

filename=f"report_{file_id}.pdf",

504

media_type="application/pdf",

505

headers={"X-File-ID": str(file_id)}

506

)

507

```

508

509

### Form Data Handling

510

511

```python

512

from fastapi import FastAPI, Request, Form, File, UploadFile

513

from fastapi.responses import HTMLResponse

514

515

app = FastAPI()

516

517

@app.get("/form", response_class=HTMLResponse)

518

async def show_form():

519

return """

520

<html>

521

<body>

522

<form action="/submit-form" method="post" enctype="multipart/form-data">

523

<input type="text" name="username" placeholder="Username">

524

<input type="email" name="email" placeholder="Email">

525

<input type="file" name="file">

526

<input type="submit" value="Submit">

527

</form>

528

</body>

529

</html>

530

"""

531

532

@app.post("/submit-form")

533

async def submit_form(request: Request):

534

# Access form data through request

535

form = await request.form()

536

537

return {

538

"form_data": {

539

"username": form.get("username"),

540

"email": form.get("email"),

541

"file": {

542

"filename": form["file"].filename if "file" in form else None,

543

"content_type": form["file"].content_type if "file" in form else None

544

}

545

},

546

"all_fields": list(form.keys())

547

}

548

549

@app.post("/submit-form-params")

550

async def submit_form_with_params(

551

username: str = Form(...),

552

email: str = Form(...),

553

file: UploadFile = File(...)

554

):

555

# Access form data through parameter injection

556

return {

557

"username": username,

558

"email": email,

559

"file": {

560

"filename": file.filename,

561

"content_type": file.content_type,

562

"size": len(await file.read())

563

}

564

}

565

```

566

567

### Advanced Request Processing

568

569

```python

570

from fastapi import FastAPI, Request, HTTPException

571

from fastapi.responses import JSONResponse

572

import json

573

574

app = FastAPI()

575

576

@app.middleware("http")

577

async def log_requests(request: Request, call_next):

578

# Log request details

579

print(f"Request: {request.method} {request.url}")

580

print(f"Headers: {dict(request.headers)}")

581

582

response = await call_next(request)

583

584

print(f"Response: {response.status_code}")

585

return response

586

587

@app.post("/webhook")

588

async def handle_webhook(request: Request):

589

# Verify content type

590

content_type = request.headers.get("content-type")

591

if content_type != "application/json":

592

raise HTTPException(status_code=400, detail="Content-Type must be application/json")

593

594

# Verify webhook signature (example)

595

signature = request.headers.get("x-webhook-signature")

596

if not signature:

597

raise HTTPException(status_code=400, detail="Missing webhook signature")

598

599

# Get raw body for signature verification

600

body = await request.body()

601

602

# Verify signature (simplified example)

603

expected_signature = compute_signature(body) # Your signature logic

604

if signature != expected_signature:

605

raise HTTPException(status_code=401, detail="Invalid signature")

606

607

# Parse JSON payload

608

try:

609

payload = json.loads(body)

610

except json.JSONDecodeError:

611

raise HTTPException(status_code=400, detail="Invalid JSON")

612

613

# Process webhook

614

result = process_webhook(payload) # Your processing logic

615

616

return JSONResponse(

617

content={"status": "processed", "result": result},

618

headers={"X-Webhook-ID": payload.get("id", "unknown")}

619

)

620

621

@app.get("/client-info")

622

async def get_client_info(request: Request):

623

return {

624

"client": {

625

"host": request.client.host if request.client else None,

626

"port": request.client.port if request.client else None

627

},

628

"forwarded_for": request.headers.get("x-forwarded-for"),

629

"real_ip": request.headers.get("x-real-ip"),

630

"user_agent": request.headers.get("user-agent"),

631

"accept": request.headers.get("accept"),

632

"accept_language": request.headers.get("accept-language"),

633

"referer": request.headers.get("referer")

634

}

635

```

636

637

### Response Customization

638

639

```python

640

from fastapi import FastAPI, Response, status

641

from fastapi.responses import JSONResponse

642

from datetime import datetime

643

644

app = FastAPI()

645

646

@app.get("/custom-headers")

647

async def custom_headers(response: Response):

648

# Modify response directly

649

response.headers["X-Custom-Header"] = "custom-value"

650

response.headers["X-Timestamp"] = str(datetime.now())

651

response.status_code = status.HTTP_200_OK

652

653

return {"message": "Response with custom headers"}

654

655

@app.post("/conditional-response")

656

async def conditional_response(data: dict):

657

if "error" in data:

658

return JSONResponse(

659

status_code=400,

660

content={"error": data["error"], "timestamp": str(datetime.now())},

661

headers={"X-Error-Type": "user-error"}

662

)

663

664

return JSONResponse(

665

status_code=201,

666

content={"result": "success", "data": data},

667

headers={"X-Result-Type": "success"}

668

)

669

670

@app.get("/cache-control")

671

async def cache_control():

672

return JSONResponse(

673

content={"data": "cacheable content"},

674

headers={

675

"Cache-Control": "public, max-age=3600",

676

"ETag": "unique-etag-value",

677

"Last-Modified": "Wed, 21 Oct 2023 07:28:00 GMT"

678

}

679

)

680

```