Reputation: 2305
I'd like to create specific API route which will be used only WebSocket (/api/events
) but in all examples of implementing WebSockets on Nest.js I stumbled upon module is imported in AppModule
and client is emitting events toward the root URL, which I can't do because I have this middleware;
frontend.middleware.ts
import { Request, Response } from 'express';
import { AppModule } from '../../app.module';
export function FrontendMiddleware(
req: Request,
res: Response,
next: Function,
) {
const { baseUrl } = req;
if (baseUrl.indexOf('/api') === 0) {
next();
} else {
res.sendFile('index.html', { root: AppModule.getStaticAssetsRootPath() });
}
}
Here is the EventGateway
and EventModule
:
event.gateway.ts
import {
SubscribeMessage,
WebSocketGateway,
WebSocketServer,
WsResponse,
} from '@nestjs/websockets';
import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Client, Server } from 'socket.io';
@WebSocketGateway({ namespace: 'events' })
export class EventGateway {
@WebSocketServer()
server: Server;
@SubscribeMessage('events')
findAll(client: Client, data: any): Observable<WsResponse<number>> {
return from([1, 2, 3]).pipe(map(item => ({ event: 'events', data: item })));
}
@SubscribeMessage('identity')
async identity(client: Client, data: number): Promise<number> {
return data;
}
}
event.module.ts
import { Module } from '@nestjs/common';
import { EventGateway } from './event.gateway';
@Module({
components: [EventGateway],
})
export class EventModule {}
Is there a way to create controller which will allow server-client communication via /api/events
?
Upvotes: 8
Views: 13439
Reputation: 151
Yes, it is possible to create the WebsocketGateway on another path. You can just use the options of the WebsocketGateway to configure the underlying IO-Connection:
E.g:
import {
SubscribeMessage,
WebSocketGateway,
WebSocketServer,
WsResponse,
} from '@nestjs/websockets';
import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Client, Server } from 'socket.io';
@WebSocketGateway({ path: '/api/events', namespace: 'events' })
export class EventGateway {
@WebSocketServer()
server: Server;
@SubscribeMessage('events')
findAll(client: Client, data: any): Observable<WsResponse<number>> {
return from([1, 2, 3]).pipe(map(item => ({ event: 'events', data: item })));
}
@SubscribeMessage('identity')
async identity(client: Client, data: number): Promise<number> {
return data;
}
}
This will start the IO-Connection on http://localhost/api/events
Remember to change the connection-path also in your client. It won't be the default /socket.io path anymore, it will be /api/events in your sample.
Upvotes: 15
Reputation: 789
Websocket is running on the server, not an endpoint. Therefore you cannot have it listen to requests under a specific route, rather just a port, which for Nest's default configuration happens to be the same as the HTTP one.
You could use a reverse proxy like Nginx to redirect the requests towards /api/events
facing the Websocket server and also handle the redirection to index.html
without changing even the Websocket server's port. Then you would not need the FrontendMiddleware
class at all. It is also better since the application does not take the burden of managing request redirections.
Upvotes: -3