A NestJS microservice transport layer for UDP communication.
- Full NestJS Integration - Seamless microservices architecture support
- UDP Client & Server - Complete implementation for both sides using Node.js dgram module
- Dual Pattern Support - Message patterns (request-response) and event patterns (fire-and-forget)
- Highly Customizable - Flexible socket options and custom implementations
- TypeScript First - Full type safety and IntelliSense support
- Node.js: v20.0.0 or higher
- NestJS: v11.0.0 or higher
npm install @pirumu/nest-udpyarn add @pirumu/nest-udppnpm add @pirumu/nest-udpCreate a UDP microservice server using Node.js dgram:
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions } from '@nestjs/microservices';
import { ServerUdp } from '@pirumu/nest-udp';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
strategy: new ServerUdp({
host: '0.0.0.0',
port: 41234,
transport: 'udp4',
}),
},
);
await app.listen();
}
bootstrap();import { Controller } from '@nestjs/common';
import { MessagePattern, EventPattern, Payload, Ctx } from '@nestjs/microservices';
import { UdpContext } from '@pirumu/nest-udp';
@Controller()
export class AppController {
// Request-Response pattern
@MessagePattern('calculate')
calculate(@Payload() data: { a: number; b: number }) {
return { result: data.a + data.b };
}
// Fire-and-forget pattern
@EventPattern('user.created')
handleUserCreated(@Payload() user: any, @Ctx() context: UdpContext) {
console.log('New user:', user);
}
}Register the UDP client in your module:
import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { ClientUdp } from '@pirumu/nest-udp';
@Module({
imports: [
ClientsModule.register({
clients: [
{
name: 'UDP_SERVICE',
customClass: ClientUdp,
options: {
host: 'localhost',
port: 41234,
transport: 'udp4',
},
},
],
}),
],
})
export class AppModule {}import { Injectable, Inject } from '@nestjs/common';
import { ClientUdp } from '@pirumu/nest-udp';
import { lastValueFrom } from 'rxjs';
@Injectable()
export class AppService {
constructor(
@Inject('UDP_SERVICE') private readonly client: ClientUdp
) {}
async calculate(a: number, b: number) {
// Request-response (waits for reply)
return lastValueFrom(
this.client.send('calculate', { a, b })
);
}
notifyUserCreated(user: any) {
// Fire-and-forget (no reply expected)
this.client.emit('user.created', user).subscribe();
}
}Built on top of Node.js dgram module (available since Node.js v20).
| Property | Type | Default | Description |
|---|---|---|---|
host |
string |
'0.0.0.0' |
Server bind address |
port |
number |
3000 |
Server listening port |
transport |
'udp4' | 'udp6' |
'udp4' |
UDP protocol version |
socketOptions |
dgram.SocketOptions |
{} |
Node.js dgram socket options |
bindOptions |
dgram.BindOptions |
{} |
Node.js dgram bind options |
| Property | Type | Default | Description |
|---|---|---|---|
host |
string |
'localhost' |
Target server address |
port |
number |
3000 |
Target server port |
type |
'udp4' | 'udp6' |
'udp4' |
UDP protocol version |
socketClass |
Type<UdpSocket> |
JsonUdpSocket |
Custom socket implementation |
socketOptions |
dgram.SocketOptions |
{} |
Node.js dgram socket options |
bindOptions |
dgram.BindOptions |
{} |
Node.js dgram bind options |
Send a message and expect a response (request-response pattern).
client.send('getUserById', { id: 123 })
.subscribe(user => console.log(user));Emit an event without expecting a response (fire-and-forget pattern).
client.emit('order.placed', { orderId: 456 })
.subscribe(() => console.log('Event emitted'));Manually establish connection. Called automatically by send() and emit().
await client.connect();Close the UDP connection and cleanup resources.
client.close();Implement your own socket class:
import { UdpSocket } from '@pirumu/nest-udp';
import * as dgram from 'node:dgram';
class MsgPackUdpSocket extends UdpSocket {
sendMessage(message: any, host: string, port: number): void {
const buffer = msgpack.encode(message);
this.udpSocket.send(buffer, port, host);
}
}
// Use in client configuration
ClientsModule.register({
clients: [{
name: 'UDP_SERVICE',
customClass: ClientUdp,
options: {
socketClass: MsgPackUdpSocket,
// ... other options
},
}],
})Leverage RxJS operators for robust error handling:
import { catchError, retry, timeout } from 'rxjs/operators';
import { of } from 'rxjs';
client.send('unreliable-service', { data: 'test' })
.pipe(
timeout(5000),
retry(3),
catchError(error => {
console.error('Request failed:', error);
return of({ error: 'Service unavailable' });
})
)
.subscribe(result => console.log(result));Access UDP-specific context information including dgram RemoteInfo:
@MessagePattern('echo')
handleEcho(@Payload() data: any, @Ctx() context: UdpContext) {
const remoteInfo = context.getRemoteInfo();
console.log(`From: ${remoteInfo.address}:${remoteInfo.port}`);
console.log(`Family: ${remoteInfo.family}`);
console.log(`Size: ${remoteInfo.size} bytes`);
return data;
}Access the underlying dgram socket for advanced use cases:
import * as dgram from 'node:dgram';
@Injectable()
export class AppService {
constructor(
@Inject('UDP_SERVICE') private readonly client: ClientUdp
) {}
async onModuleInit() {
await this.client.connect();
// Access native dgram socket
const socket = this.client.unwrap<dgram.Socket>();
// Use native dgram APIs
socket.setMulticastTTL(128);
socket.setBroadcast(true);
}
}Contributions are welcome! Please feel free to submit a Pull Request.
This project is MIT licensed.
- Issues: GitHub Issues
Made with love by Pirumu