CanxJS's event system provides a simple observer implementation, allowing you to subscribe and listen to various events that occur in your application.
Events in CanxJS serve as a great way to decouple various aspects of your application, since a single event can have multiple listeners that do not depend on each other.
An event class is a simple container for the information related to the event. For example, let's generate an OrderShipped event:
bun run canx make:event OrderShippedThis will create a new class in src/events/OrderShipped.ts:
import { events } from 'canxjs';
export class OrderShipped {
constructor(
public readonly orderId: number
) {}
/**
* Dispatch this event
*/
static dispatch(orderId: number): void {
events.emit('order:shipped', new OrderShipped(orderId));
}
}You can register event listeners in your application bootstrap or service providers. The events helper provides a fluent API for this.
import { events } from 'canxjs';
import { OrderShipped } from './events/OrderShipped';
// Listen for a specific event
events.on('order:shipped', (event: OrderShipped) => {
console.log(`Order ${event.orderId} was shipped!`);
});
// Listen once
events.once('app:ready', () => {
console.log('Application is ready!');
});You can emit events asynchronously using emitAsync. This will await all registered handlers before proceeding.
await events.emitAsync('user:registered', user);If you prefer a class-based approach for listeners, you can use the @Listen decorator within your service classes.
import { Listen, Injectable } from 'canxjs';
@Injectable()
export class UserSubscriber {
@Listen('user:registered')
async onUserRegistered(event: UserRegistered) {
// Send welcome email...
}
}CanxJS automatically generates AsyncAPI 2.6+ specifications for your event-driven services using decorators. This provides a Swagger-like experience for events.
import { AsyncApiChannel, AsyncApiMessage, Controller } from 'canxjs';
class OrderPayload {
@AsyncApiMessage({ summary: "Order ID" })
id: string;
}
@Controller('orders')
export class OrderController {
@AsyncApiChannel({
name: 'order/created',
publish: true,
summary: 'Emitted when a new order is placed'
})
@AsyncApiMessage({ payload: OrderPayload })
createOrder() {
// Your logic...
}
}To generate the spec file, use the AsyncApiGenerator in your bootstrap file:
const document = AsyncApiGenerator.createDocument(app, {
info: { title: 'Event API', version: '1.0.0' },
servers: {
dev: { url: 'ws://localhost:3000', protocol: 'ws' }
}
});
// Save the document to your filesystem manually or serve it
await Bun.write('./asyncapi.json', JSON.stringify(document, null, 2));