SpaceNode
A file upload API with multipart parsing, file validation, and storage.
import { createApp } from 'SpaceNode'
import { writeFile, mkdir } from 'node:fs/promises'
import { randomUUID } from 'node:crypto'
const app = await createApp({
bodyLimit: 10 * 1024 * 1024, // 10 MB for file uploads
pipe: ['cors', 'logger'],
})
const UPLOAD_DIR = './uploads'
await mkdir(UPLOAD_DIR, { recursive: true })
// Upload a single file
app.setRoute('POST', '/upload', async ({ files, send, check, error }) => {
check(files && files.length > 0, 400, 'No file uploaded')
const file = files[0]
const allowed = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf']
check(allowed.includes(file.mimetype), 400, 'Only JPEG, PNG, WebP, and PDF allowed')
const ext = file.filename.split('.').pop()
const id = randomUUID()
const path = `${UPLOAD_DIR}/${id}.${ext}`
await writeFile(path, file.data)
send(201, {
id,
filename: file.filename,
mimetype: file.mimetype,
size: file.size,
url: `/files/${id}.${ext}`,
})
})
// Upload multiple files
app.setRoute('POST', '/upload/batch', async ({ files, send, check }) => {
check(files && files.length > 0, 400, 'No files uploaded')
check(files.length <= 5, 400, 'Max 5 files at a time')
const results = []
for (const file of files) {
const id = randomUUID()
const ext = file.filename.split('.').pop()
await writeFile(`${UPLOAD_DIR}/${id}.${ext}`, file.data)
results.push({ id, filename: file.filename, size: file.size })
}
send(201, { uploaded: results })
})
app.listen(3000)
# Upload a single file
curl -X POST http://localhost:3000/upload \
-F "file=@photo.jpg"
# Upload multiple files
curl -X POST http://localhost:3000/upload/batch \
-F "file1=@photo1.jpg" \
-F "file2=@photo2.png"