HTTP and SQLite

Accept and validate JSON

Read a JSON request body, validate unknown input with Zod, and return a clear creation or client-error response.

9 minute lesson

~~~

TypeScript types do not validate data sent over HTTP. A client can send any JSON value.

Define the input with Zod:

import { z } from 'zod'

const NoteInput = z.object({
  title: z.string().trim().min(1).max(120),
})

Add a POST handler beside the existing GET handler:

let nextId = 3

const notesRoute = {
  GET: () => Response.json(notes),
  POST: async (request: Request) => {
    const json = await request.json().catch(() => null)
    const result = NoteInput.safeParse(json)

    if (!result.success) {
      return Response.json(
        { error: 'Send a title between 1 and 120 characters' },
        { status: 400 },
      )
    }

    const note = {
      id: nextId++,
      title: result.data.title,
    }

    notes.push(note)

    return Response.json(note, { status: 201 })
  },
}

Use it in the server:

Bun.serve({
  routes: {
    '/api/notes': notesRoute,
  },
})

Create a note with curl:

curl -X POST http://localhost:3000/api/notes \
  -H 'Content-Type: application/json' \
  -d '{"title":"Test the API"}'

A valid request returns the new note with status 201 Created. Invalid JSON and invalid titles return 400 Bad Request.

Validate at the boundary. After safeParse() succeeds, the rest of the handler can use a known input shape.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →