Handling File Uploads
| Property | Value |
| Content-Type | multipart/form-data; boundary=... |
| Multiple fields | Mix files and text fields |
| Per-part headers | Content-Disposition, Content-Type |
| Memory | Stream to disk for large files |
2. Implementing Chunked Uploads
Example: Tus Resumable Upload Protocol
# 1. Create upload
POST /uploads
Upload-Length: 10485760
Upload-Metadata: filename bWUucG5n
→ 201 Created
Location: /uploads/abc-123
# 2. Upload chunks (resumable)
PATCH /uploads/abc-123
Upload-Offset: 0
Content-Type: application/offset+octet-stream
<binary chunk>
→ 204 No Content
Upload-Offset: 524288
# 3. Resume after failure
HEAD /uploads/abc-123
→ Upload-Offset: 524288 (resume from here)
3. Validating File Types
| Check | Method |
| Extension | Quick filter, easy to spoof |
| MIME type (header) | Client-supplied; verify |
| Magic bytes | First N bytes of file (e.g. 89 50 4E 47 = PNG) |
| Allowlist | Whitelist accepted types only |
4. Implementing File Size Limits
| Limit | Typical |
| Per-file | 10-100 MB |
| Total request | 500 MB |
| Per-user quota | Configurable |
| Over limit response | 413 Payload Too Large |
5. Generating Presigned URLs
Client uploads directly to storage (S3, GCS, Azure Blob), bypassing API server.
Example: Presigned URL Flow
POST /uploads/presign
{"filename": "report.pdf", "contentType": "application/pdf", "size": 1048576}
→ {
"uploadUrl": "https://s3.amazonaws.com/...?X-Amz-Signature=...",
"method": "PUT",
"headers": {"Content-Type": "application/pdf"},
"expiresIn": 900,
"fileUrl": "https://cdn.example.com/files/abc123.pdf"
}
# Client then PUTs file directly to S3
6. Handling Upload Progress Tracking
| Technique | Notes |
XHR upload.onprogress | Browser-native byte tracking |
| Fetch + ReadableStream | Modern; per-chunk progress |
| Tus protocol | Server tracks Upload-Offset |
7. Implementing Direct-to-Storage Uploads
| Benefit | Tradeoff |
| Reduces API server load | CORS configuration on storage |
| Higher throughput | Pre/post-upload validation needs separate calls |
| Lower latency | Tighter coupling to storage SDK |
8. Validating File Content
| Check | Tool |
| Virus scan | ClamAV, VirusTotal |
| Image dimensions | Pillow, sharp, ImageMagick |
| EXIF stripping | Remove GPS/camera metadata |
| Office docs / PDFs | Sandboxed parsing; reject macros |
| SVG sanitization | Strip <script>, event handlers |
9. Returning Upload Status
| Status | Body |
| 201 Created | File metadata + URL |
| 202 Accepted | Async processing (virus scan, transcoding) |
| 413 Payload Too Large | File over size limit |
| 415 Unsupported Media Type | File type not allowed |
10. Handling Upload Errors
| Error | Handling |
| Network interruption | Resume via Tus or chunked retry |
| Quota exceeded | 413 with quota info |
| Storage error | 500/503 + retry guidance |
| Virus detected | 422 + cleanup uploaded file |