API reference / @chanx-js/nestjs
@chanx-js/nestjs
chanx for NestJS: consumers and topics as injectable gateways, with Nest's guards, interceptors, pipes and exception filters. Built on @chanx-js/server, so clients cannot tell it from Python's chanx.
Documentation · chanx-js · Why chanx-js?
import { Module, UseGuards } from '@nestjs/common';
import { z } from 'zod';
import type { ConnectRequest, Context } from '@chanx-js/server';
import { PingMessage, PongMessage, defineMessage } from '@chanx-js/server';
import { ChanxConsumer, ChanxModule, Ctx, On, Payload } from '@chanx-js/nestjs';
const Chat = defineMessage('chat', z.object({ text: z.string() }));
const Notice = defineMessage('notice', z.object({ text: z.string() }));
@ChanxConsumer('/ws/chat/{room}', { name: 'chat', emits: [Notice] })
export class ChatGateway {
constructor(private readonly users: UsersService) {}
authenticate({ url }: ConnectRequest) {
return this.users.fromToken(url.searchParams.get('token'));
}
@On(PingMessage, { output: PongMessage })
ping() {
return PongMessage.create();
}
@On(Chat, { output: Notice })
@UseGuards(MemberGuard)
chat(
@Payload('text') text: string,
@Ctx() ctx: Context<'/ws/chat/{room}', unknown, User, never>,
) {
return Notice.create({ text: `${ctx.params.room}: ${text}` });
}
}
@Module({
imports: [ChanxModule.forRoot()],
providers: [UsersService, ChatGateway],
})
export class AppModule {}ChanxModule finds every @ChanxConsumer and @ChanxTopic provider when the app starts and serves them on the app's HTTP server. Run Nest with emitDecoratorMetadata, as any Nest app does.
- Handlers take
@Payload()(or a property, or pipes:@Payload(new ValidationPipe())) and@Ctx(), the chanx context.@MessageBody()and@ConnectedSocket()from@nestjs/websocketswork too. - Guards, interceptors and pipes run as for a Nest WebSocket gateway; a guard sees the chanx context as the client.
- Errors: exception filters run first, and what one returns is the reply. Otherwise an
HttpExceptionorWsExceptionthrown by a handler, guard or pipe is sent as anerrorframe, and anything else is logged and sent as chanx's generic error. - DTOs:
defineMessage('chat', dtoSchema(ChatPayload))validates payloads with class-validator and documents them in AsyncAPI from@ApiPropertyorclass-validator-jsonschema. - Hooks are plain methods:
authenticate,onConnect,onDisconnecton consumers,authorize,onSubscribe,onUnsubscribeon topics, and the error hooks. - Scope: a request-scoped gateway gets an instance per connection (a topic, per subscription), with the connection as Nest's
REQUEST. - AsyncAPI in CI:
npx chanx-nestjs asyncapi dist/app.module.js -o asyncapi.jsonwrites the document without serving it;asyncapiOf(AppModule)returns it in code. - From services, inject
ChanxServicetobroadcastEvent,sendEvent,publishto a topic, or get theasyncapi()document.
ChanxModule.forRoot() takes createChanx's options (layers, camelize, ...) plus pingInterval, and asyncapi: true (or its options) to serve the AsyncAPI docs page at /asyncapi and the document at /asyncapi.json and /asyncapi.yaml. forRootAsync({ useFactory, inject }) takes them from other providers, such as ConfigService.