Skip to content

Commit e2a459e

Browse files
Add FastAPI HTTP request benchmark
1 parent cdbf33b commit e2a459e

File tree

4 files changed

+121
-0
lines changed

4 files changed

+121
-0
lines changed

pyperformance/data-files/benchmarks/MANIFEST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ django_template <local>
4242
dulwich_log <local>
4343
docutils <local>
4444
fannkuch <local>
45+
fastapi <local>
4546
float <local>
4647
genshi <local>
4748
go <local>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[project]
2+
name = "pyperformance_bm_fastapi"
3+
requires-python = ">=3.10"
4+
dependencies = [
5+
"pyperf",
6+
"fastapi",
7+
"uvicorn",
8+
"httpx",
9+
]
10+
urls = {repository = "https://github.com/python/pyperformance"}
11+
dynamic = ["version"]
12+
13+
[tool.pyperformance]
14+
name = "fastapi"
15+
tags = "apps"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
annotated-doc==0.0.3
2+
annotated-types==0.7.0
3+
anyio==4.11.0
4+
certifi==2025.10.5
5+
click==8.3.0
6+
fastapi==0.121.0
7+
h11==0.16.0
8+
httpcore==1.0.9
9+
httpx==0.28.1
10+
idna==3.11
11+
pydantic==2.12.4
12+
pydantic-core==2.41.5
13+
sniffio==1.3.1
14+
starlette==0.49.3
15+
typing-extensions==4.15.0
16+
typing-inspection==0.4.2
17+
uvicorn==0.38.0
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
"""
2+
Test the performance of simple HTTP serving with FastAPI.
3+
4+
This benchmark tests FastAPI's request handling, including:
5+
- Path parameter extraction and validation
6+
- Pydantic model serialization
7+
- JSON response encoding
8+
9+
The bench serves a REST API endpoint that returns JSON objects,
10+
simulating a typical web application scenario.
11+
12+
Author: Savannah Ostrowski
13+
"""
14+
15+
import asyncio
16+
import socket
17+
import time
18+
from typing import List
19+
20+
import httpx
21+
import pyperf
22+
import uvicorn
23+
from fastapi import FastAPI
24+
from pydantic import BaseModel
25+
26+
HOST = "127.0.0.1"
27+
28+
CONCURRENCY = 150
29+
30+
class Item(BaseModel):
31+
id: int
32+
name: str
33+
price: float
34+
tags: List[str] = []
35+
36+
app = FastAPI()
37+
38+
@app.get("/items/{item_id}", response_model=Item)
39+
async def get_item(item_id: int):
40+
return {
41+
"id": item_id,
42+
"name": "Sample Item",
43+
"price": 9.99,
44+
"tags": ["sample", "item", "fastapi"]
45+
}
46+
47+
48+
async def run_server_and_benchmark(loops):
49+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
50+
s.bind((HOST, 0))
51+
s.listen(1)
52+
port = s.getsockname()[1]
53+
54+
config = uvicorn.Config(app, host=HOST, port=port, log_level="error")
55+
server = uvicorn.Server(config)
56+
server_task = asyncio.create_task(server.serve())
57+
58+
await asyncio.sleep(0.5)
59+
60+
async with httpx.AsyncClient() as client:
61+
t0 = time.perf_counter()
62+
63+
for i in range(loops):
64+
tasks = [
65+
client.get(f"http://{HOST}:{port}/items/{i}")
66+
for _ in range(CONCURRENCY)
67+
]
68+
responses = await asyncio.gather(*tasks)
69+
for response in responses:
70+
response.raise_for_status()
71+
data = response.json()
72+
assert data["id"] == i
73+
assert "tags" in data
74+
75+
elapsed = time.perf_counter() - t0
76+
77+
server.should_exit = True
78+
await server_task
79+
return elapsed
80+
81+
def bench_fastapi(loops):
82+
return asyncio.run(run_server_and_benchmark(loops))
83+
84+
85+
if __name__ == "__main__":
86+
runner = pyperf.Runner()
87+
runner.metadata['description'] = "Test the performance of HTTP requests with FastAPI"
88+
runner.bench_time_func("fastapi_http", bench_fastapi)

0 commit comments

Comments
 (0)