PAS7 Studio

Body parsing і validation у Bun.js: JSON, uploads, streams і payload limits

Практичний deep dive по body parsing middleware у Bun.js: JSON, FormData, uploads, streams, payload limits, schema validation, idempotency, content-type checks, безпечний порядок middleware і погані практики.

14 трав. 2026 р.· 11 хв читання· Технології
Кому підійдеBackend інженериFull-stack розробникиTech leadsКоманди, що будують JSON API, webhook endpoints або upload flows на Bun
Технічна ілюстрація body parsing pipeline у Bun.js з JSON, uploads, streams і validation
Гайд / СеріяСтаття серії

Bun.js Middleware Production Guide 2026

Серія про production middleware у Bun.js: огляд, безпека, performance, observability, rate limiting, body parsing, WebSocket/SSE і тестування request pipeline.

У Bun, як і в Web API загалом, request body не є безкінечною змінною, яку можна читати скільки завгодно. Це stream. Якщо один шар прочитав його без договору з рештою pipeline, наступний шар може отримати порожній body, помилку або неочікувану поведінку.

Саме тому body parsing не варто ховати в глобальний middleware “про всяк випадок”. Він має бути route-aware, content-type aware і size-aware.

У цій статті розбираємо, як зробити parsing і validation так, щоб вони захищали API, а не створювали memory pressure, security holes і дивні баги.

JSON, FormData, uploads і streams потребують різних pipelines.
Payload limit має стояти до дорогого parsing, а не після нього.
Schema validation має створити typed parsed context, а не просто “перевірити щось”.
Uploads мають security policy окремо від JSON API.

Це фінальний chapter поточного roadmap по Bun middleware. Він закриває тему request body - найчастіше джерело memory, security і validation проблем у API.

Ментальна модель body ownership: хто читає body, хто валідовує, хто передає parsed value.
JSON middleware: content-type, size limit, parsing, schema validation, typed context.
FormData і uploads: multipart, file size, extension/MIME allowlist, storage, malware scanning. [4]
Streams і великі payload-и: коли не можна буферизувати все в пам'ять.
Idempotency keys для POST/PUT flows, які можуть повторюватись.
Погані практики: глобальний req.json(), body logs, parsing після auth/rate limit у неправильному порядку, validation без strip/strict policy.

Найважливіше правило: request body має одного власника. Якщо кілька middleware намагаються читати body самостійно, pipeline стає крихким.

01

Перевірити route і method

Не читайте body для GET/HEAD або routes, де body не потрібен. Це економить latency і прибирає випадкові side effects.

02

Перевірити content-type

JSON route має приймати application/json, upload route - multipart/form-data або конкретний binary content-type. Не парсіть усе як JSON.

03

Застосувати size limit

Якщо ліміт перевіряється після await req.json() або await req.formData(), він уже не захищає пам'ять від великого payload.

04

Прочитати body один раз

Використовуйте json(), formData(), arrayBuffer() або stream залежно від route. Parsed value передавайте в context.

05

Валідувати і передати typed value

Schema validation має повертати типізований результат або стабільний 400/422, а не залишати handler здогадуватись.

Висновок

Body ownership робить pipeline передбачуваним: handler отримує готовий parsed value, а не сам вирішує, що сталося з stream.

Bun HTTP server працює з Web Request/Response моделлю. Тому базові методи body reading знайомі з Fetch API: json(), text(), formData(), arrayBuffer(), blob() і stream. [1][2]

МетодКоли використовуватиЩо повертаєГоловна обережність
req.json()JSON API, webhook JSON, config mutationsParsed JavaScript valueПадає на invalid JSON, потребує size/content-type/schema checks
req.formData()Forms, multipart uploads, mixed text/file fieldsFormData з fields/filesМоже буферизувати великі upload-и, потрібні file limits і storage policy
req.arrayBuffer()Binary payload, signatures, raw webhook verificationArrayBufferМоже різко збільшити memory pressure на великих payloads
req.text()Plain text, raw signature input, small text payloadsStringНе підходить для великих streams або uploads
req.body streamВеликі payload-и, streaming ingestion, custom parsersReadableStream або nullПотрібно самому контролювати backpressure, limits і errors

Вибір body API має залежати від route. JSON, FormData, binary і streams не треба пропускати через один універсальний parser.

Скріншот секції request-body-apis

Висновок

Універсальний body parser зручний на старті, але production API краще розділяти за content-type і route purpose.

Для JSON routes вам потрібен не просто await req.json(), а маленький gate: перевірити content-type, приблизний content-length, прочитати body, обробити parse errors, провалідовати schema, передати typed result.

Мінімальний native Bun патерн:

TS
type JsonContext<T> = { body: T };
type JsonHandler<T> = (req: Request, ctx: JsonContext<T>) => Promise<Response> | Response;

function jsonRoute<T>(schema: { parse: (value: unknown) => T }, handler: JsonHandler<T>) {
  return async (req: Request) => {
    const contentType = req.headers.get("content-type") ?? "";
    if (!contentType.includes("application/json")) {
      return Response.json({ error: "unsupported_media_type" }, { status: 415 });
    }

    const contentLength = Number(req.headers.get("content-length") ?? 0);
    if (contentLength > 256_000) {
      return Response.json({ error: "payload_too_large" }, { status: 413 });
    }

    try {
      const raw = await req.json();
      const body = schema.parse(raw);
      return handler(req, { body });
    } catch {
      return Response.json({ error: "invalid_request_body" }, { status: 400 });
    }
  };
}

У реальному коді краще розділити parse error і validation error, щоб повертати 400 для invalid JSON і 422 для schema mismatch, якщо ваш API contract це підтримує. Але головне - handler уже не читає body сам.

Практичне правило

JSON middleware має створювати typed body context. Якщо handler знову викликає req.json(), ownership не працює.

File upload - одна з найризикованіших поверхонь API. OWASP File Upload Cheat Sheet радить обмежувати extension, перевіряти content type, змінювати filename, задавати size limits, зберігати файли поза webroot, перевіряти permissions і за потреби сканувати файли. [4]

У Bun upload route не має проходити через той самий JSON middleware. Upload потребує окремих правил: що можна завантажувати, який максимум, куди зберігати, як називати, коли сканувати, чи потрібна асинхронна обробка.

Важливо відрізняти metadata validation від file validation. Поля форми можна валідовувати schema, але файл треба перевіряти окремо: size, declared MIME, magic bytes, extension allowlist, malware scanning, storage path.

Не довіряйте оригінальному filename.
Не зберігайте uploads у public webroot без потреби.
Не приймайте будь-який MIME або extension.
Не читайте великі файли в пам'ять, якщо їх можна stream-ити в storage.
Не логайте file contents або sensitive metadata.

Upload route має окремий pipeline: size limit, type allowlist, scan/validation і безпечне storage рішення.

Скріншот секції uploads

Якщо route приймає великий payload, ingestion stream, media upload або long-running transfer, arrayBuffer() і formData() можуть бути неправильним вибором. Вони зручні, але можуть змусити runtime тримати значний обсяг даних у пам'яті.

Streaming flow вимагає іншого мислення: ранні limits, backpressure, abort handling, timeout policy, storage streaming, partial failures і cleanup. Це не “звичайний JSON endpoint з великим body”.

Для streams observability теж інша: total request time може бути довгим і нормальним, тому важливо міряти throughput, bytes accepted, time to first byte, storage errors і client aborts.

Великі payload-и треба stream-ити через pipeline, а не перетворювати на один великий buffer заради зручності handler.

Скріншот секції streams

Висновок

Як тільки payload може бути великим, body parsing стає performance і reliability темою, а не просто validation helper.

Schema validation має не тільки перевірити типи. Вона має визначити, що робити з невідомими полями, coercion, defaults і partial updates.

Strict schema

Добре для security-sensitive API: невідомі поля відхиляються. Мінус - клієнти можуть ламатися при зайвих полях.

Strip unknown

Зручно для public API: зайві поля відкидаються, business logic бачить чистий shape. Важливо логувати schema mismatch обережно.

Passthrough

Корисно тільки коли API справді приймає dynamic payload. Інакше це створює ризик mass assignment або прихованих полів.

Coercion everywhere

Автоматичне перетворення типів може бути зручним, але іноді приховує помилки клієнта. Для money, permissions і security flags краще бути суворішим.

Висновок

Validation policy має бути частиною API contract. Якщо кожен route трактує unknown fields по-своєму, клієнти і security review швидко втрачають передбачуваність.

POST/PUT flows з оплатою, замовленнями, webhook retries, file ingestion і background jobs мають окрему проблему: клієнт може повторити request, бо не отримав response або отримав timeout. Body validation тут має працювати разом з idempotency key.

Idempotency middleware зазвичай перевіряє Idempotency-Key, route group, subject/tenant і hash body. Якщо той самий key приходить з іншим body, це має бути conflict, а не повторне виконання mutation.

Це не обов'язково для кожного JSON route, але для дорогих або irreversible operations це часто дешевше, ніж розбирати дублікати в бізнес-даних після інциденту.

Практичне правило

Якщо mutation небезпечно виконати двічі, body validation має включати idempotency story.

Ці помилки найчастіше з'являються, коли команда намагається зробити “універсальний body middleware” для всього API.

Глобальний await req.json() для всіх routes.

Читання body у кількох middleware без передачі parsed context.

Payload limit після parsing, а не до нього.

Один parser для JSON, multipart, binary і streams.

Логування raw body у production.

Відсутній 415 Unsupported Media Type для неправильного content-type.

Uploads зберігаються з оригінальним filename у public директорію.

Validation пропускає unknown fields у security-sensitive endpoints.

Немає відмінності між invalid JSON (400) і schema mismatch (422), якщо API contract це потребує.

Large payload routes не мають timeout, abort і cleanup policy.

Рев'ю правило

Body parser має бути route-specific. Якщо він “працює для всього”, він майже точно не захищає важливі edge cases.

Перед запуском Bun API у staging або production пройдіть цей список для кожного класу endpoint: JSON, upload, stream, webhook і mutation.

Body owner визначений

Один middleware або route-level gate читає body і передає parsed context.

Content-type перевіряється

JSON, multipart, binary і streams мають різні accepted content-types.

Size limit стоїть рано

Ліміт застосовується до parsing або streaming ingestion, а не після повного buffer.

Schema validation має policy

Strict, strip або passthrough поведінка зафіксована і однакова для route class.

Uploads мають security controls

Extension/MIME allowlist, size limits, safe filename, storage policy, permissions і scanning за потреби.

Streams мають abort/cleanup

Client abort, timeout, partial writes і storage errors обробляються явно.

Errors стабільні

400, 413, 415, 422 і 500 мають прогнозований JSON contract.

Body не логиться

У logs йде request id, route, status, validation error class, але не raw body або file contents.

Bun дає зручну Web Request/Response модель, але саме тому легко забути, що body - це stream, а не звичайний object. Добрий middleware не читає body “про всяк випадок”. Він знає route, method, content-type, size limit і schema.

JSON, uploads, streams і binary payloads потребують різних pipelines. У production універсальний parser часто стає джерелом memory pressure, validation ambiguity і security risk.

Найкращий підхід простий: один власник body, ранній limit, правильний parser, typed validation result, стабільний error contract і окрема upload/stream policy. Це закриває більшість проблем ще до handler.

Чи можна читати `req.json()` у кількох middleware?

Не варто. Request body є stream, і його треба читати один раз у відповідальному шарі. Parsed value передавайте в context або handler. Повторне читання без контракту створює крихкі bugs.

Де ставити payload limit?

Якомога раніше: до дорогого parsing або під час streaming ingestion. Якщо ви спочатку робите `await req.json()` або `await req.formData()`, великий payload уже потрапив у пам'ять.

Чи підходить один middleware для JSON і uploads?

Для production краще ні. JSON, multipart uploads, binary і streams мають різні security, memory і validation вимоги. Їх треба розділяти по route classes.

Що повертати для invalid body?

`400` для invalid syntax або malformed body, `413` для завеликого payload, `415` для неправильного content-type, `422` для schema mismatch, якщо ваш API contract розрізняє validation errors.

Чи треба логувати body при validation error?

Ні за замовчуванням. Логуйте request id, route, error class, field names або safe summary. Raw body може містити PII, credentials або великі payload-и.

Коли потрібен idempotency key?

Для mutations, які небезпечно виконати двічі: payments, orders, uploads, webhook processing, job creation. Idempotency key має бути пов'язаний із subject/tenant/route і hash body.

Джерела підтверджують Web Request body methods, Bun HTTP server model і security baseline для uploads та content validation.

Перевірено: 14 трав. 2026 р.Актуально для: Bun 1.3.xАктуально для: Bun.serve routesАктуально для: Fetch API RequestАктуально для: FormDataАктуально для: ReadableStreamАктуально для: TypeScript validationПеревірено з: Request.json()Перевірено з: Request.formData()Перевірено з: Request.arrayBuffer()Перевірено з: Bun.serve middleware compositionПеревірено з: Zod-style schema validation

PAS7 Studio може допомогти спроєктувати validation pipeline для Bun, Hono або Elysia: JSON schemas, upload security, payload limits, stream ingestion, idempotency keys, stable error contract і observability.

Це особливо корисно для SaaS, webhook endpoints, file ingestion, AI/automation flows і міграцій з Express/Fastify, де body parsing часто розкиданий по middleware, handlers і validators.

Ви тут05/05

Body parsing і validation у Bun.js: JSON, uploads, streams і payload limits

Попередня
Наступна

Пов'язані статті

ai-assistants

Скільки коштує розробка AI асистента у 2026: RAG чатбот, база знань, CRM, Telegram та підтримка

Практичний гід для бізнесу: від чого залежить ціна розробки AI асистента у 2026 році, що входить у RAG чатбот, інтеграції з CRM, Telegram, guardrails, оцінювання, моніторинг і супровід.

blogs

AI для розробки лендінгів: де він реально прискорює запуск, а де псує конверсію

Дослідження про використання AI у розробці лендінгів: v0, Webflow AI, Builder.io, Framer-подібні AI builders, генерація UX, copy, SEO, персоналізація, A/B тести, ризики шаблонності, безпеки, доступності та технічного боргу.

growth

AI SEO / GEO у 2026: ваші наступні клієнти — не люди, а агенти

Пошук зміщується від кліків до відповідей. Боти та AI-агенти сканують, цитують, рекомендують і дедалі частіше купують. Дізнайтесь, що таке AI SEO / GEO, чому класичного SEO вже недостатньо, і як PAS7 Studio допомагає брендам перемагати у «агентному» вебі.

blogs

Найпотужніший чіп від Apple? M5 Pro і M5 Max б'ють рекорди

Аналітичний розбір Apple M5 Pro і M5 Max станом на березень 2026 року. Пояснюємо, чому ці чіпи можна вважати найпотужнішими професійними ноутбучними SoC від Apple, як вони виглядають на тлі M4 Pro, M4 Max, M1 Pro, M1 Max і що показують у порівнянні з актуальними Intel та AMD.

Професійна розробка для вашого бізнесу

Створюємо сучасні веб-рішення та боти для бізнесу. Дізнайтеся, як ми можемо допомогти вам досягти цілей.