BFF input validation
The NestJS BFF (apps/bff) validates incoming requests with Zod via decorators and ZodValidationPipe. Failures become FrontendInputValidationException → 400 with issues (see Error handling).
Decorators are exported from common/validation:
TypeScript
import { Controller, Get, Post } from '@nestjs/common'
import { ZodBody, ZodQuery, ZodParam } from '../../common/validation'
import { z } from 'zod'
const CreateExampleBodySchema = z.object({ title: z.string().min(1) })
@Controller('example')
export class ExampleController {
@Get(':productSlug')
getOne(
@ZodParam(z.string().min(1), 'productSlug') productSlug: string,
@ZodQuery(z.object({ page: z.coerce.number().optional() }))
query: { page?: number }
) {
return { productSlug, query }
}
@Post()
create(@ZodBody(CreateExampleBodySchema) body: z.infer<typeof CreateExampleBodySchema>) {
return body
}
}
ZodValidationPiperuns on those parameters; invalid input → 400 with Zodissues.- Schemas are imported from @core/contracts (or inline
zwhere the codebase does).
Outgoing (responses to the presentation)
Parse or strip service results with the same contract schemas so you never return shapes the client cannot handle:
TypeScript
import { z } from 'zod'
const MainNavigationResponseSchema = z.object({ items: z.array(z.object({ id: z.string() })) })
async function getNavigationExample(
navigationService: { getNavigation: () => Promise<unknown> }
): Promise<z.infer<typeof MainNavigationResponseSchema>> {
return MainNavigationResponseSchema.strip().parse(await navigationService.getNavigation())
}
Real usage: e.g. navigation.service.ts patterns.
Related
Back to Input validation · Back to Validation & resilience · Back to How to work with SHOPin