Example: File Upload Service

A file upload API with multipart parsing, file validation, and storage.

app.js

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)

Testing with cURL

# 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"