Lær, hvordan du opbygger en chat-API i realtid, der udnytter kraften i WebSockets ved hjælp af NestJS.

NestJS er en populær ramme til at bygge server-side applikationer med Node.js. Med sin understøttelse af WebSockets er NestJS velegnet til udvikling af chat-applikationer i realtid.

Så hvad er WebSockets, og hvordan kan du bygge en chat-app i realtid i NestJS?

Hvad er WebSockets?

WebSockets er en protokol til vedvarende, realtids- og tovejskommunikation mellem en klient og en server.

I modsætning til i HTTP, hvor en forbindelse lukkes, når en anmodningscyklus er fuldført mellem klienten og serveren, en WebSocket-forbindelse holdes åben og lukker ikke, selv efter et svar er blevet returneret for en anmodning.

Billedet nedenfor er en visualisering af, hvordan en WebSocket-kommunikation mellem en server og klient fungerer:

For at etablere tovejskommunikation sender klienten en WebSocket-handshake-anmodning til serveren. Anmodningshovederne indeholder en sikker WebSocket-nøgle (Sec-WebSocket-Key

instagram viewer
), og en Opgradering: WebSocket header som sammen med Tilslutning: Opgradering header fortæller serveren om at opgradere protokollen fra HTTP til WebSocket og holde forbindelsen åben. At lære om WebSockets i JavaScript hjælper med at forstå konceptet endnu bedre.

Opbygning af en realtidschat-API ved hjælp af NestJS WebSocket-modulet

Node.js leverer to store WebSockets-implementeringer. Den første er ws som implementerer bare WebSockets. Og den anden er socket.io, som giver flere funktioner på højt niveau.

NestJS har moduler til begge dele socket.io og ws. Denne artikel bruger socket.io modul til prøveapplikationens WebSocket-funktioner.

Koden brugt i dette projekt er tilgængelig i en GitHub-depot. Det anbefales, at du kloner det lokalt for bedre at forstå mappestrukturen og se, hvordan alle koderne interagerer med hinanden.

Projektopsætning og installation

Åbn din terminal og generer en ny NestJS-app ved hjælp af rede ny kommando (f.eks. nest ny chat-app). Kommandoen genererer en ny mappe, der indeholder projektfilerne. Nu er du klar til at starte udviklingsprocessen.

Konfigurer en MongoDB-forbindelse

For at bevare chatbeskederne i applikationen skal du have en database. Denne artikel bruger MongoDB-databasen til vores NestJS-applikation, og den nemmeste måde at komme i gang på er at opsætte en MongoDB-klynge i skyen og få din MongoDB URL. Kopier URL'en og gem den som MONGO_URI variabel i din .env fil.

Du ville også få brug for Mongoose senere, når du foretager forespørgsler til MongoDB. Installer det ved at køre npm installere mongoose i din terminal.

I den src mappe, skal du oprette en fil kaldet mongo.config.ts og indsæt følgende kode i den.

importere { registerAs } fra'@nestjs/config';

/**
* Mongo-databaseforbindelseskonfiguration
*/

eksportStandard registerAs('mongodb', () => {
konst { MONGO_URI } = proces.env; // fra .env-fil
Vend tilbage {
uri:`${MONGO_URI}`,
};
});

Dit projekts main.ts filen skal se sådan ud:

importere { NestFactory } fra'@nestjs/core';
importere { AppModule } fra'./app.modul';
importere * som cookieParser fra'cookie-parser'
importere hjelm fra'hjelm'
importere { Logger, ValidationPipe } fra'@nestjs/common';
importere { setupSwagger } fra'./utils/swagger';
importere { HttpExceptionFilter } fra'./filters/http-undtagelse.filter';

asynkronfungerebootstrap() {
konst app = vente NestFactory.create (AppModule, { cors: rigtigt });
app.enableCors({
oprindelse: '*',
legitimationsoplysninger: rigtigt
})
app.use (cookieParser())
app.useGlobalPipes(
ny ValidationPipe({
hvidliste: rigtigt
})
)
konst logger = ny Logger('Main')

app.setGlobalPrefix('api/v1')
app.useGlobalFilters(ny HttpExceptionFilter());

opsætningSwagger (app)
app.use (hjelm())

vente app.listen (AppModule.port)

// log docs
konst baseUrl = AppModule.getBaseUrl (app)
konst url = `http://${baseUrl}:${AppModule.port}`
logger.log(`API-dokumentation tilgængelig på ${url}/docs`);
}
bootstrap();

Opbygning af chatmodulet

For at komme i gang med chatfunktionen i realtid er det første trin at installere NestJS WebSockets-pakkerne. Dette kan gøres ved at køre følgende kommando i terminalen.

npm installer @nestjs/websockets @nestjs/platform-socket.io @types/socket.io

Efter installation af pakkerne skal du generere chatmodulet ved at køre følgende kommandoer

nest g modul chats
nest g controller chats
nest g service chats

Når du er færdig med at generere modulet, er næste trin at oprette en WebSockets-forbindelse i NestJS. Lave en chat.gateway.ts fil inde i chats mappe, er det her gatewayen, der sender og modtager beskeder, implementeres.

Indsæt følgende kode i chat.gateway.ts.

importere {
MessageBody,
Abonner besked,
WebSocketGateway,
WebSocketServer,
} fra'@nestjs/websockets';
importere { Server } fra'socket.io';

@WebSocketGateway()
eksportklasseChatGateway{
@WebSocketServer()
server: Server;
// lyt efter send_message begivenheder
@SubscribeMessage('Send besked')
listenForMessages(@MessageBody() besked: streng) {
det her.server.sockets.emit('modtag_besked', besked);
}
}

Godkendelse af tilsluttede brugere

Autentificering er en væsentlig del af webapplikationer, og det er ikke anderledes for en chatapplikation. Funktionen til at godkende klientforbindelser til socket findes i chats.service.ts som vist her:

@Injicerbar()
eksportklasseChatservice{
konstruktør(privat authService: AuthService) {}

asynkron getUserFromSocket (socket: Socket) {
lade auth_token = socket.handshake.headers.authorization;
// få selve tokenet uden "Bearer"
auth_token = auth_token.split(' ')[1];

konst bruger = det her.authService.getUserFromAuthenticationToken(
auth_token
);

hvis (!bruger) {
kasteny WsException('Ugyldige legitimationsoplysninger.');
}
Vend tilbage bruger;
}
}

Det getUserFromSocket metode bruger getUserFromAuthenticationToken for at hente den aktuelt loggede bruger fra JWT-tokenet ved at udtrække Bearer-tokenet. Det getUserFromAuthenticationToken funktion er implementeret i auth.service.ts fil som vist her:

offentlig asynkron getUserFromAuthenticationToken (token: streng) {
konst nyttelast: JwtPayload = det her.jwtService.verify (token, {
hemmelighed: det her.configService.get('JWT_ACCESS_TOKEN_SECRET'),
});

konst bruger-id = nyttelast.sub

hvis (bruger ID) {
Vend tilbagedet her.usersService.findById (brugerId);
}
}

Den aktuelle stikdåse sendes som parameter til getUserFromSocket når håndtereForbindelse metode til ChatGateway gennemfører OnGatewayConnection interface. Dette gør det muligt at modtage beskeder og information om den aktuelt tilsluttede bruger.

Koden nedenfor viser dette:

// chat.gateway.ts
@WebSocketGateway()
eksportklasseChatGatewayredskaberOnGatewayConnection{
@WebSocketServer()
server: Server;

konstruktør(private chatsService: ChatsService) {}

asynkron handleConnection (socket: Socket) {
ventedet her.chatsService.getUserFromSocket (socket)
}

@SubscribeMessage('Send besked')
asynkron listenForMessages(@MessageBody() besked: streng, @ConnectedSocket() socket: Socket) {

konst bruger = ventedet her.chatsService.getUserFromSocket (socket)
det her.server.sockets.emit('modtag_besked', {
besked,
bruger
});
}
}

Du kan referere til de filer, der er involveret i godkendelsessystemet ovenfor i GitHub-depot at se de komplette koder (inklusive import), for en bedre forståelse af implementeringen.

Vedvarende chats til databasen

For at brugerne kan se deres beskedhistorik, skal du have et skema til at gemme beskeder. Opret en ny fil kaldet message.schema.ts og indsæt koden nedenfor i den (husk at importere din bruger skema eller tjek lageret for en).

importere { Bruger } fra'./../users/schemas/user.schema';
importere { Prop, Schema, SchemaFactory } fra"@nestjs/mongoose";
importere mangust, { Dokument } fra"mangust";

eksport type MessageDocument = Besked & Dokument;

@Skema({
tilJSON: {
getters: rigtigt,
virtuelle: rigtigt,
},
tidsstempler: rigtigt,
})
eksportklasseBesked{
@Rekvisit({ påkrævet: rigtigt, enestående: rigtigt })
besked: streng

@Rekvisit({ type: mangust. Skema. Typer. ObjectId, ref: 'Bruger' })
bruger: Bruger
}

konst MessageSchema = SchemaFactory.createForClass (Message)

eksport { MessageSchema };

Nedenfor er en implementering af tjenester til at oprette en ny besked og få alle beskeder ind chats.service.ts.

importere { Besked, MessageDocument } fra'./meddelelse.skema'; 
importere { Socket } fra'socket.io';
importere { AuthService } fra'./../auth/auth.service';
importere { Injicerbar } fra'@nestjs/common';
importere { WsException } fra'@nestjs/websockets';
importere { InjectModel } fra'@nestjs/mongoose';
importere { Model } fra'mangust';
importere { MessageDto } fra'./dto/message.dto';

@Injicerbar()
eksportklasseChatservice{
konstruktør(privat authService: AuthService, @InjectModel (Message.name) privat beskedModel: Model) {}
...
asynkron createMessage (meddelelse: MessageDto, bruger ID:streng) {
konst newMessage = nydet her.messageModel({...message, userId})
vente newMessage.save
Vend tilbage Ny besked
}
asynkron getAllMessages() {
Vend tilbagedet her.messageModel.find().populate('bruger')
}
}

Det Besked Dto er implementeret i en besked.dto.ts fil i dto mappe i chats vejviser. Du kan også finde det i depotet.

Du skal tilføje besked model og skema til listen over importer i chats.modul.ts.

importere { Besked, MessageSchema } fra'./meddelelse.skema';
importere { Modul } fra'@nestjs/common';
importere { ChatGateway } fra'./chats.gateway';
importere { ChatsService } fra'./chats.service';
importere { MongooseModule } fra'@nestjs/mongoose';

@Modul({
importerer: [MongooseModule.forFeature([
{ navn: Message.name, skema: MessageSchema }
])],
controllere: [],
udbydere: [ChatsService, ChatGateway]
})
eksportklasseChatsModule{}

Endelig få_alle_beskeder hændelseshandler er tilføjet til ChatGateway klasse i chat.gateway.ts som det ses i følgende kode:

// importerer...

@WebSocketGateway()
eksportklasseChatGatewayredskaberOnGatewayConnection{
...

@SubscribeMessage('få_alle_beskeder')
asynkron getAllMessages(@ConnectedSocket() socket: Socket) {

ventedet her.chatsService.getUserFromSocket (socket)
konst beskeder = ventedet her.chatsService.getAllMessages()

det her.server.sockets.emit('modtag_besked', Beskeder);

Vend tilbage Beskeder
}
}

Når en tilsluttet klient (bruger) udsender få_alle_beskeder begivenhed, vil alle deres beskeder blive hentet, og når de udsender Send besked, en besked oprettes og gemmes i databasen og sendes derefter til alle andre tilsluttede klienter.

Når du er færdig med alle ovenstående trin, kan du starte din applikation vha npm run start: dev, og test det med en WebSocket-klient som Postman.

Opbygning af realtidsapplikationer med NestJS

Selvom der er andre teknologier til at bygge realtidssystemer, er WebSockets meget populære og nemme at implementere i mange tilfælde, og de er den bedste mulighed for chatapplikationer.

Realtidsapplikationer er ikke kun begrænset til chatapplikationer, andre eksempler omfatter videostreaming eller opkaldsapplikationer og live-vejrapplikationer, og NestJS giver fantastisk værktøj til at bygge i realtid apps.