Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

The request body

The request body is the data a client sends with POST, PUT or PATCH: a new post, a comment, a file. Hono reads the body asynchronously, so the handler is declared async and uses await.

JSON

An API usually accepts JSON. Add a route for creating a post in src/index.ts:

// src/index.ts
app.post('/posts', async (c) => {
  const data = await c.req.json()
  return c.json({ received: data }, 201)
})

Send a request from the terminal:

curl -X POST http://localhost:3000/posts \
  -H "Content-Type: application/json" \
  -d '{"title": "New post", "body": "Text"}'

The server returns the object you sent inside the received field, with code 201.

Saving the post

Now add the post to the posts array:

// src/index.ts
type NewPost = { title: string; body: string }
 
app.post('/posts', async (c) => {
  const data = await c.req.json<NewPost>()
  const post = { id: posts.length + 1, title: data.title, body: data.body }
  posts.push(post)
  return c.json(post, 201)
})

The generic type in c.req.json<NewPost>() only tells TypeScript which fields to expect. It checks nothing: the client can send anything. Real validation comes in the zod lesson. After the request, GET /posts shows three posts — until the server restarts, because the array lives in memory.

Form data

An HTML form sends data not as JSON but as application/x-www-form-urlencoded or multipart/form-data. Both are handled by c.req.parseBody():

// src/index.ts
app.post('/comments', async (c) => {
  const body = await c.req.parseBody()
  const author = String(body.author ?? '')
  const text = String(body.text ?? '')
  return c.text(`${author} writes: ${text}`)
})

Check it like this:

curl -X POST http://localhost:3000/comments -d "author=Anna" -d "text=Great post"

The response is "Anna writes: Great post". A field value from parseBody() is a string, or a File object if the form uploaded a file.

Other ways

MethodWhen to use
c.req.json()a JSON body
c.req.parseBody()a regular HTML form
c.req.formData()you need a standard FormData object
c.req.text()the body as a string
c.req.arrayBuffer()binary data
// src/index.ts
app.post('/upload', async (c) => {
  const form = await c.req.formData()
  const file = form.get('cover')
  return c.text(file instanceof File ? `File ${file.name}` : 'No file')
})

formData() returns the same FormData as in the browser, with get() and getAll() methods.

Common mistake

The body contains invalid JSON: single quotes instead of double ones, a trailing comma, a cut-off string. c.req.json() then throws a parse error and the client gets code 500, even though the client is at fault. Do not trust the request body: the zod validator from the next chapter answers bad data with code 400, and the error lesson shows how to shape the response.

Thanks for reading!

Donate to the site — we work hard for you.