Тело запроса
Тело запроса — данные, которые клиент отправляет вместе с POST, PUT или PATCH: новую статью, комментарий, файл. Hono читает тело асинхронно, поэтому обработчик объявляют с async и пишут await.
JSON
API обычно принимает JSON. Добавьте маршрут создания статьи в src/index.ts:
// src/index.ts
app.post('/posts', async (c) => {
const data = await c.req.json()
return c.json({ received: data }, 201)
})Отправьте запрос из терминала:
curl -X POST http://localhost:3000/posts \
-H "Content-Type: application/json" \
-d '{"title": "Новая статья", "body": "Текст"}'Сервер вернёт отправленный объект внутри поля received и код 201.
Сохранение статьи
Теперь добавим статью в массив posts:
// 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)
})Обобщённый тип в c.req.json<NewPost>() только подсказывает TypeScript, какие поля ожидаются. Он ничего не проверяет: клиент может прислать что угодно. Настоящую проверку добавит урок о zod. После запроса GET /posts покажет уже три статьи — до перезапуска сервера, ведь массив живёт в памяти.
Данные формы
HTML-форма отправляет данные не в JSON, а в формате application/x-www-form-urlencoded или multipart/form-data. Для обоих случаев есть 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} пишет: ${text}`)
})Проверить можно так:
curl -X POST http://localhost:3000/comments -d "author=Anna" -d "text=Отличная статья"Ответ — «Anna пишет: Отличная статья». Значение поля в parseBody() — строка или объект File, если форма загружала файл.
Другие способы
| Метод | Когда использовать |
|---|---|
c.req.json() | тело в формате JSON |
c.req.parseBody() | обычная HTML-форма |
c.req.formData() | нужен стандартный объект FormData |
c.req.text() | тело как строка |
c.req.arrayBuffer() | двоичные данные |
// 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.name}` : 'Файла нет')
})formData() возвращает тот же FormData, что и в браузере, с методами get() и getAll().
Частая ошибка
В теле приходит неверный JSON: одинарные кавычки вместо двойных, лишняя запятая, обрезанная строка. c.req.json() в таком случае выбрасывает ошибку разбора, и клиент получает код 500, хотя виноват он сам. Не доверяйте телу запроса: валидатор zod из следующей главы отвечает на неверные данные кодом 400, а урок об ошибках показывает, как оформить ответ.