p2g: add File Uploads tutorial — UploadFile, multiple files, form fields, async processing
swadhinbiswas committed 3 months ago
f3451c0
1 parent eb82030
commit f3451c0
1 file changed
+113 -0
Showing 1 changed file+113-0
▼docs_site/src/content/docs/tutorials/file-uploads.md
+113-0
| @@ -0,0 +1,113 @@ | ||
1 | +--- | |
2 | +title: File Uploads | |
3 | +description: Handle file uploads with multipart form data using UploadFile and File annotations. | |
4 | +--- | |
5 | + | |
6 | +JustAPI provides robust support for file uploads via `multipart/form-data` using Rust's `multer` parser, with streaming to temporary files to avoid memory exhaustion. | |
7 | + | |
8 | +## Basic File Upload | |
9 | + | |
10 | +```python | |
11 | +from justapi import JustAPIApp, UploadFile, File | |
12 | + | |
13 | +app = JustAPIApp() | |
14 | + | |
15 | + | |
16 | +@app.post("/upload/") | |
17 | +async def upload_file(request, file: UploadFile = File(...)): | |
18 | + return { | |
19 | + "filename": file.filename, | |
20 | + "content_type": file.content_type, | |
21 | + "size": file.size, | |
22 | + } | |
23 | +``` | |
24 | + | |
25 | +```bash | |
26 | +curl -X POST http://127.0.0.1:8000/upload/ \ | |
27 | + -F "[email protected]" | |
28 | +# Output: {"filename":"example.txt","content_type":"text/plain","size":1234} | |
29 | +``` | |
30 | + | |
31 | +## Multiple Files | |
32 | + | |
33 | +```python | |
34 | +@app.post("/upload-multiple/") | |
35 | +async def upload_multiple(request, files: list[UploadFile] = File(...)): | |
36 | + return { | |
37 | + "files": [ | |
38 | + {"name": f.filename, "size": f.size} for f in files | |
39 | + ], | |
40 | + "count": len(files), | |
41 | + } | |
42 | +``` | |
43 | + | |
44 | +```bash | |
45 | +curl -X POST http://127.0.0.1:8000/upload-multiple/ \ | |
46 | + -F "[email protected]" \ | |
47 | + -F "[email protected]" | |
48 | +``` | |
49 | + | |
50 | +## File + Form Fields Together | |
51 | + | |
52 | +```python | |
53 | +@app.post("/profile/") | |
54 | +async def create_profile( | |
55 | + request, | |
56 | + avatar: UploadFile = File(...), | |
57 | + name: str = Form(...), | |
58 | + bio: str = Form(""), | |
59 | +): | |
60 | + return { | |
61 | + "name": name, | |
62 | + "bio": bio, | |
63 | + "avatar_filename": avatar.filename, | |
64 | + "avatar_size": avatar.size, | |
65 | + } | |
66 | +``` | |
67 | + | |
68 | +```bash | |
69 | +curl -X POST http://127.0.0.1:8000/profile/ \ | |
70 | + -F "[email protected]" \ | |
71 | + -F "name=Alice" \ | |
72 | + -F "bio=Hello world" | |
73 | +``` | |
74 | + | |
75 | +## The `UploadFile` Object | |
76 | + | |
77 | +| Attribute/Method | Type | Description | | |
78 | +|---|---|---| | |
79 | +| `filename` | str | Original filename from the client | | |
80 | +| `content_type` | str | MIME type of the file | | |
81 | +| `file` | str | Path to the temporary file on disk | | |
82 | +| `size` | int | File size in bytes | | |
83 | +| `.read()` | bytes | Read file contents into memory | | |
84 | + | |
85 | +## How It Works | |
86 | + | |
87 | +1. The Rust `multer` parser streams multipart data as it arrives | |
88 | +2. Each uploaded file is written to a temporary file on disk (not held in memory) | |
89 | +3. The `UploadFile` Python object provides a zero-copy view of the file path | |
90 | +4. Temporary files are cleaned up when the request completes | |
91 | + | |
92 | +## Asynchronous Processing | |
93 | + | |
94 | +For large files, process asynchronously to avoid blocking: | |
95 | + | |
96 | +```python | |
97 | +import aiofiles | |
98 | +from justapi import UploadFile, File | |
99 | + | |
100 | + | |
101 | +@app.post("/process-large/") | |
102 | +async def process_large(request, file: UploadFile = File(...)): | |
103 | + # Read and process in chunks | |
104 | + content = await file.read() | |
105 | + result = await process_content(content) | |
106 | + return {"result": result} | |
107 | +``` | |
108 | + | |
109 | +## Next Steps | |
110 | + | |
111 | +- [WebSockets & SSE](/tutorials/websockets-sse/) — Real-time bidirectional communication | |
112 | +- [Database Integration](/tutorials/database-integration/) — Store file metadata in DB | |
113 | +- [Background Tasks](/tutorials/background-tasks/) — Process files after the response | |
0 | 114 | |