Skip to content

Commit 8e3612e

Browse files
authored
Improve FastAPI Python docs and adds frontend example. (#32662)
1 parent b2a5687 commit 8e3612e

1 file changed

Lines changed: 135 additions & 39 deletions

File tree

  • src/content/docs/workers/languages/python/packages

src/content/docs/workers/languages/python/packages/fastapi.mdx

Lines changed: 135 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,127 @@ products:
99
- workers
1010
---
1111

12-
import { Render } from "~/components";
12+
import { Render, WranglerConfig } from "~/components";
1313

1414
The FastAPI package is supported in Python Workers.
1515

16-
FastAPI applications use a protocol called the [Asynchronous Server Gateway Interface (ASGI)](https://asgi.readthedocs.io/en/latest/). This means that FastAPI never reads from or writes to a socket itself. An ASGI application expects to be hooked up to an ASGI server, typically [uvicorn](https://uvicorn.dev/).
16+
FastAPI applications use a protocol called the [Asynchronous Server Gateway Interface (ASGI)](https://asgi.readthedocs.io/en/latest/).
17+
This means that FastAPI never reads from or writes to a socket itself. An ASGI application expects to be hooked up to an ASGI server,
18+
typically [uvicorn](https://uvicorn.dev/).
1719
The ASGI server handles all of the raw sockets on the application’s behalf.
1820

19-
The Python Workers provides [an ASGI server](https://github.com/cloudflare/workers-py/blob/main/packages/runtime-sdk/src/asgi.py)
21+
The Python Workers provide [an ASGI server](https://github.com/cloudflare/workers-py/blob/main/packages/runtime-sdk/src/asgi.py)
2022
that you can use directly in your Python Worker, which lets you use FastAPI in Python Workers.
2123

22-
## Get Started
24+
## Quick Start
2325

24-
Clone the `cloudflare/python-workers-examples` repository and run the FastAPI example:
26+
To get started with FastAPI in Python Workers, follow these steps:
2527

28+
2. Create a `src/main.py` file with your FastAPI application:
29+
```python
30+
from fastapi import FastAPI
31+
32+
app = FastAPI()
33+
34+
@app.get("/")
35+
def read_root():
36+
return {"Hello": "World"}
37+
38+
import asgi
39+
from workers import WorkerEntrypoint
40+
41+
class Default(WorkerEntrypoint):
42+
async def fetch(self, request):
43+
return await asgi.fetch(app, request, self.env)
44+
```
45+
46+
3. Create a `wrangler.jsonc` file to configure your Worker:
47+
48+
<WranglerConfig>
49+
50+
```jsonc
51+
{
52+
"name": "my-fastapi-app",
53+
"main": "src/main.py",
54+
"compatibility_date": "$today",
55+
"compatibility_flags": ["python_workers"],
56+
}
57+
```
58+
</WranglerConfig>
59+
60+
4. Create a `pyproject.toml` file to manage your dependencies:
61+
```toml
62+
[project]
63+
name = "my-fastapi-app"
64+
version = "0.1.0"
65+
requires-python = ">=3.13"
66+
dependencies = [
67+
"fastapi",
68+
]
69+
70+
[dependency-groups]
71+
dev = [
72+
"workers-py",
73+
"workers-runtime-sdk"
74+
]
75+
```
76+
77+
5. Run your Worker locally:
2678
```bash
27-
git clone https://github.com/cloudflare/python-workers-examples
28-
cd python-workers-examples/03-fastapi
2979
uv run pywrangler dev
3080
```
3181

32-
### Example code
82+
## Serve a frontend
3383

34-
```python
84+
You can serve a single-page application (SPA) or any static frontend alongside your FastAPI backend by using [Workers Static Assets](/workers/static-assets/).
85+
86+
This is equivalent to FastAPI's native [`app.frontend()`](https://fastapi.tiangolo.com/tutorial/frontend/) method, which serves a static build directory as low-priority routes so that API path operations are checked first. The difference is where the files live: `app.frontend()` reads files from the local filesystem, while on Workers the static assets are served from Cloudflare's globally distributed asset store through the `ASSETS` binding. This means your frontend files are not bundled inside the Worker itself, keeping the bundle small.
87+
88+
Place your frontend build output (for example, HTML, CSS, and JavaScript files) in a directory such as `./public/`. Then configure your Wrangler file with an `assets` block that includes a `binding` and sets `run_worker_first` to `true`. This ensures every request reaches your FastAPI Worker first, so your API routes take priority over static files.
89+
90+
Add a catch-all route at the end of your FastAPI app that proxies unmatched requests to the assets binding:
91+
92+
<WranglerConfig>
93+
94+
```jsonc
95+
{
96+
"name": "my-fastapi-app",
97+
"main": "src/worker.py",
98+
"compatibility_date": "$today",
99+
"compatibility_flags": ["python_workers"],
100+
"assets": {
101+
"directory": "./public/",
102+
"binding": "ASSETS",
103+
"run_worker_first": true
104+
}
105+
}
106+
```
107+
</WranglerConfig>
108+
109+
Be sure to create a `pyproject.toml` file to manage your dependencies:
110+
111+
```toml
112+
[project]
113+
name = "my-fastapi-app"
114+
version = "0.1.0"
115+
requires-python = ">=3.13"
116+
dependencies = [
117+
"fastapi",
118+
]
119+
120+
[dependency-groups]
121+
dev = [
122+
"workers-py",
123+
"workers-runtime-sdk"
124+
]
125+
```
126+
127+
Then write your worker:
128+
129+
```python title="src/worker.py"
35130
from workers import WorkerEntrypoint
36131
from fastapi import FastAPI, Request
37-
from pydantic import BaseModel
132+
from fastapi.responses import Response
38133
import asgi
39134

40135
class Default(WorkerEntrypoint):
@@ -43,33 +138,34 @@ class Default(WorkerEntrypoint):
43138

44139
app = FastAPI()
45140

46-
@app.get("/")
47-
async def root():
48-
return {"message": "Hello, World!"}
49-
50-
@app.get("/env")
51-
async def root(req: Request):
52-
env = req.scope["env"]
53-
return {"message": "Here is an example of getting an environment variable: " + env.MESSAGE}
54-
55-
class Item(BaseModel):
56-
name: str
57-
description: str | None = None
58-
price: float
59-
tax: float | None = None
60-
61-
@app.post("/items/")
62-
async def create_item(item: Item):
63-
return item
64-
65-
@app.put("/items/{item_id}")
66-
async def create_item(item_id: int, item: Item, q: str | None = None):
67-
result = {"item_id": item_id, **item.dict()}
68-
if q:
69-
result.update({"q": q})
70-
return result
71-
72-
@app.get("/items/{item_id}")
73-
async def read_item(item_id: int):
74-
return {"item_id": item_id}
141+
@app.get("/api/hello")
142+
async def api_hello():
143+
return {"message": "Hello from the API"}
144+
145+
# Catch-all: proxy everything else to Workers Static Assets.
146+
# This is the Workers equivalent of app.frontend("/", directory="dist").
147+
@app.get("/{path:path}")
148+
async def frontend(path: str, request: Request):
149+
env = request.scope["env"]
150+
asset_url = f"https://assets.local/{path}"
151+
resp = await env.ASSETS.fetch(asset_url)
152+
body = await resp.bytes()
153+
headers = dict(resp.headers)
154+
return Response(content=body, status_code=resp.status, headers=headers)
75155
```
156+
157+
You can run this worker locally using `uv run pywrangler dev`.
158+
159+
With this setup, a request to `/api/hello` is handled by FastAPI, while a request to `/index.html` or any other path is served from the `./public/` directory through the assets binding.
160+
161+
For more information on configuring static assets, refer to the [Workers Static Assets documentation](/workers/static-assets/).
162+
163+
## More examples
164+
165+
Clone the `cloudflare/python-workers-examples` repository and run the FastAPI examples there:
166+
167+
```bash
168+
git clone https://github.com/cloudflare/python-workers-examples
169+
cd python-workers-examples/03-fastapi
170+
uv run pywrangler dev
171+
```

0 commit comments

Comments
 (0)