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
▼docs_site/src/content/docs/tutorials/file-uploads.md
+113-0
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
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
47
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
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