Skip to content

fix(http): parse body before guards and return parsed body synchronously#208

Open
nicoske wants to merge 1 commit into
FOSSFORGE:mainfrom
nicoske:fix-http-body-before-guards
Open

fix(http): parse body before guards and return parsed body synchronously#208
nicoske wants to merge 1 commit into
FOSSFORGE:mainfrom
nicoske:fix-http-body-before-guards

Conversation

@nicoske

@nicoske nicoske commented Jul 22, 2026

Copy link
Copy Markdown

Fixes #206

Moves body parsing ahead of guard execution in the route registry and stores the parsed body on the request right away, not only when pipes run. The body getter returns the parsed value synchronously once it exists; before parsing it still returns a Promise, and await req.body behaves the same in both states. Pipes keep overwriting the stored body as before, and streaming content types (multipart, octet-stream) are still skipped.

Motivation: guards commonly authorize against payload fields, and libraries like Nestia's @TypedBody read request.body without awaiting. Both get a pending Promise on this platform while working fine on Express.

The declared getter type changes from Promise<unknown> to unknown. The only pattern that could notice is calling .then() on it directly instead of awaiting, which nothing in the code base or docs does.

Malformed JSON keeps producing the same response it did before the reorder; the new e2e pins that down.

New e2e suite: test/http/guards-body-access.e2e.spec.ts (guard reads the body synchronously, allow/deny based on payload, synchronous read in the handler, malformed JSON). Lint, unit (975) and e2e (239) suites are green on Node 24.

Guards ran before body parsing, and request.body kept returning a
Promise even after the pipeline had parsed the body. Any guard that
reads request.body (the usual shape of an auth guard that binds a token
to payload fields) saw a pending Promise instead of the payload, and
the same happened to schema validators that read request.body without
awaiting (e.g. Nestia's @TypedBody). On Express none of this is an
issue because body-parser middleware runs ahead of the guards.

Parse the body before guard execution and store it on the request, and
make the body getter return the parsed value directly once it is
available. Awaiting request.body keeps working in both states, and
pipes overwrite the stored body as before. Streaming content types
(multipart, octet-stream) are untouched.

The trade-off is that a request rejected by a guard now pays the body
parse cost first, which is the same behavior as Express with global
body-parser middleware.
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: eb09a339-d855-4ca5-9480-8bd1048dc5ff

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Guards run before body parsing, so request.body is a pending Promise inside canActivate

1 participant