Skip to main content

Validation

@AsyncApiMessage and @AsyncApiHeaders turn a payload into JSON Schema for the generated document. The package supports both validation worlds Nest users already use, and never introduces a parallel schema reflector.

class-validator DTOs (default)

Pass a DTO class. The generator resolves it through the same @nestjs/swagger chain that documents HTTP bodies, so the event-side schema matches the HTTP-side schema for the same DTO. Document the DTO with @ApiProperty (and validate at runtime with class-validator as usual).

import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNumber } from 'class-validator';

export class OrderPlacedDto {
@ApiProperty()
@IsString()
orderId!: string;

@ApiProperty()
@IsNumber()
total!: number;
}
@AsyncApiMessage(OrderPlacedDto, { name: 'OrderPlaced' })
@AsyncApiHeaders(OrderHeadersDto)
publishOrderPlaced(): void {}

The DTO is registered once under components.schemas, including any nested DTOs it references, and the message's payload is a $ref to it. A DTO reused across several messages is emitted a single time.

This path requires the optional peer @nestjs/swagger. If it is missing, the generator throws an actionable error telling you to install it or pass a pre-computed schema instead.

Zod payloads (optional)

For applications using Zod, convert the schema once with Zod 4's native z.toJSONSchema() and pass the resulting { name, schema } source. The generator registers the schema verbatim — it never reflects over Zod itself.

import { z } from 'zod';
import { JsonSchemaSource } from '@nest-native/asyncapi';

export const MetricReportedSchema = z.object({
name: z.string().min(1),
value: z.number(),
unit: z.enum(['ms', 'count', 'bytes']),
reportedAt: z.iso.datetime(),
});

export const metricReportedMessage: JsonSchemaSource = {
name: 'MetricReported',
schema: z.toJSONSchema(MetricReportedSchema, { target: 'draft-7' }),
};
@AsyncApiMessage(metricReportedMessage, { summary: 'A single metric sample.' })
publishMetricReported(): void {}

zod is an optional peer. It is only needed in application code that produces the schema source — the package itself never imports it.

Mixing Both

Both styles coexist in one application. The showcase sample uses class-validator DTOs for orders and a Zod payload for shipments, in the same document. Pick per message based on how that part of the application already validates.

Name Collisions

Schema and message names must be unique. Registering two structurally different schemas (or messages) under the same name is a build failure, surfacing an accidental collision instead of silently overwriting a definition. Rename one of the DTOs or schema sources so each component name is unique.

Content Type

@AsyncApiMessage defaults contentType to application/json. Override it when a message uses a different encoding:

@AsyncApiMessage(AvroPayloadDto, { contentType: 'application/avro' })
publishAvro(): void {}

For runnable examples, see sample/01-validation-class-validator and sample/02-validation-zod.