Skip to content

Validate a request body

Reject malformed JSON bodies before your handler runs and read typed fields from scope.input or ctx.extract.

AI generated, pending review Updated 10 days ago · Flare 0.3

You want a POST route that rejects a malformed JSON body with a 400 before your handler runs, and hands the handler typed, validated fields. Put a body schema on the route descriptor.

  1. Define a body schema from @flare-ts/lib/schema.
  2. Pass it in route options as { body: schema }.
  3. Read the validated body from scope.input.body.
import { FlareHost, FlareResponse } from "@flare-ts/core";
import { node } from "@flare-ts/core/node";
import { schema, str, int } from "@flare-ts/lib/schema";
const host = new FlareHost(node);
host.http.post(
"/users",
{ body: schema({ name: str.min(1), age: int.min(0) }) },
(_ctx, scope) => {
const { body } = scope.input;
return new FlareResponse(201, { name: body.name, age: body.age });
},
);
const app = host.build();
app.run();

Body validation runs after before middleware and immediately before the handler. A present-but-invalid body returns 400 with field errors before the handler runs. An empty or missing body arrives as body === null and is not rejected, so guard for it when a field is required.

Group descriptors in httpContract and use ctx.extract:

import { ControllerBase, FlareHost, httpContract } from "@flare-ts/core";
import { Post } from "@flare-ts/core/decorators";
import { node } from "@flare-ts/core/node";
import { model, str, int } from "@flare-ts/lib/schema";
class CreateUser extends model({ name: str.min(1), age: int.min(0) }) {}
const UserContract = httpContract({
create: { body: CreateUser },
});
class UsersController extends ControllerBase {
public static override deps = [];
public static override state = [];
public static override contract = UserContract;
@Post("")
create() {
const { body } = this.ctx.extract(UserContract.create);
return this.created({ name: body.name, age: body.age });
}
}
const host = new FlareHost(node);
host.http.controller("/users", UsersController);
const app = host.build();
app.run();
  • Validation happens once per request at the boundary. You don’t re-validate inside the handler.
  • Add route and query to the same descriptor. Inline handlers read all fields from scope.input.
  • To cap body size, add maxBodyBytes to the descriptor. Oversized bodies return 413.