Lær hvordan du bygger en sanntids chat-API som utnytter kraften til WebSockets ved hjelp av NestJS.

NestJS er et populært rammeverk for å bygge applikasjoner på serversiden med Node.js. Med sin støtte for WebSockets er NestJS godt egnet for utvikling av chat-applikasjoner i sanntid.

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

Hva er WebSockets?

WebSockets er en protokoll for vedvarende, sanntids- og toveiskommunikasjon mellom en klient og en server.

I motsetning til i HTTP hvor en tilkobling lukkes når en forespørselssyklus er fullført mellom klienten og serveren, en WebSocket-tilkobling holdes åpen og lukkes ikke selv etter at et svar har blitt returnert for en be om.

Bildet nedenfor er en visualisering av hvordan en WebSocket-kommunikasjon mellom en server og klient fungerer:

For å etablere toveis kommunikasjon, sender klienten en WebSocket-håndtrykkforespørsel til serveren. Forespørselshodene inneholder en sikker WebSocket-nøkkel (Sec-WebSocket-Key), og en

instagram viewer
Oppgradering: WebSocket header som sammen med Tilkobling: Oppgradering header forteller serveren om å oppgradere protokollen fra HTTP til WebSocket, og holde tilkoblingen åpen. Lære om WebSockets i JavaScript bidrar til å forstå konseptet enda bedre.

Bygge en Real-Time Chat API ved å bruke NestJS WebSocket Module

Node.js tilbyr to store WebSockets-implementeringer. Den første er ws som implementerer bare WebSockets. Og den andre er socket.io, som gir flere funksjoner på høyt nivå.

NestJS har moduler for begge socket.io og ws. Denne artikkelen bruker socket.io modul for eksempelapplikasjonens WebSocket-funksjoner.

Koden som brukes i dette prosjektet er tilgjengelig i en GitHub-depot. Det anbefales at du kloner det lokalt for bedre å forstå katalogstrukturen og se hvordan alle kodene samhandler med hverandre.

Prosjektoppsett og installasjon

Åpne terminalen din og generer en ny NestJS-app ved hjelp av reir ny kommando (f.eks. nest ny chat-app). Kommandoen genererer en ny katalog som inneholder prosjektfilene. Nå er du klar til å starte utviklingsprosessen.

Sett opp en MongoDB-tilkobling

For å fortsette chat-meldingene i applikasjonen, trenger du en database. Denne artikkelen bruker MongoDB-databasen for NestJS-applikasjonen vår, og den enkleste måten å løpe på er å sette opp en MongoDB-klynge i skyen og få din MongoDB URL. Kopier URL-en og lagre den som MONGO_URI variabel i din .env fil.

Du vil også trenge Mongoose senere når du gjør spørsmål til MongoDB. Installer den ved å kjøre npm installer mongoose i terminalen din.

I src mappen, opprett en fil som heter mongo.config.ts og lim inn følgende kode i den.

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

/**
* Mongo-databasetilkoblingskonfigurasjon
*/

eksportmisligholde registerAs('mongodb', () => {
konst { MONGO_URI } = prosess.env; // fra .env-fil
komme tilbake {
uri:`${MONGO_URI}`,
};
});

Prosjektet ditt main.ts filen skal se slik ut:

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

asynkronfunksjonStøvelhempe() {
konst app = avvente NestFactory.create (AppModule, { cors: ekte });
app.enableCors({
opprinnelse: '*',
legitimasjon: ekte
})
app.use (cookieParser())
app.useGlobalPipes(
ny ValidationPipe({
hviteliste: ekte
})
)
konst logger = ny Logger('Hoved')

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

setupSwagger (app)
app.use (hjelm())

avvente app.listen (AppModule.port)

// log docs
konst baseUrl = AppModule.getBaseUrl (app)
konst url = `http://${baseUrl}:${AppModule.port}`
logger.log(`API-dokumentasjon tilgjengelig på ${url}/docs`);
}
Støvelhempe();

Bygge chat-modulen

For å komme i gang med sanntids chat-funksjonen, er det første trinnet å installere NestJS WebSockets-pakkene. Dette kan gjøres ved å kjøre følgende kommando i terminalen.

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

Etter å ha installert pakkene, må du generere chattemodulen ved å kjøre følgende kommandoer

nest g module chatter
nest g controller chatter
nest g service-chatter

Når du er ferdig med å generere modulen, er neste trinn å opprette en WebSockets-tilkobling i NestJS. Lage en chat.gateway.ts fil inne i chatter mappen, er det her gatewayen som sender og mottar meldinger implementeres.

Lim inn følgende kode i chat.gateway.ts.

import {
MessageBody,
Abonner på melding,
WebSocketGateway,
WebSocketServer,
} fra'@nestjs/websockets';
import { Server } fra'socket.io';

@WebSocketGateway()
eksportklasseChatGateway{
@WebSocketServer()
server: Server;
// lytt etter send_message-hendelser
@SubscribeMessage('sende melding')
listenForMessages(@MessageBody() melding: string) {
dette.server.sockets.emit('motta_melding', beskjed);
}
}

Autentisere tilkoblede brukere

Autentisering er en viktig del av nettapplikasjoner, og det er ikke annerledes for en chat-applikasjon. Funksjonen for å autentisere klientforbindelser til stikkontakten finnes i chats.service.ts som vist her:

@Injiserbar()
eksportklasseChatsService{
konstruktør(privat authService: AuthService) {}

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

konst bruker = dette.authService.getUserFromAuthenticationToken(
auth_token
);

hvis (!bruker) {
kasteny WsException('Ugyldige legitimasjon.');
}
komme tilbake bruker;
}
}

De getUserFromSocket metoden bruker getUserFromAuthenticationToken for å hente den påloggede brukeren fra JWT-tokenet ved å trekke ut Bearer-tokenet. De getUserFromAuthenticationToken funksjonen er implementert i auth.service.ts fil som vist her:

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

konst userId = nyttelast.sub

hvis (bruker-ID) {
komme tilbakedette.usersService.findById (userId);
}
}

Gjeldende stikkontakt sendes som parameter til getUserFromSocket når handleConnection Metode av ChatGateway implementerer OnGatewayConnection grensesnitt. Dette gjør det mulig å motta meldinger og informasjon om den tilkoblede brukeren.

Koden nedenfor demonstrerer dette:

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

konstruktør(private chatsService: ChatsService) {}

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

@SubscribeMessage('sende melding')
asynkron listenForMessages(@MessageBody() melding: string, @ConnectedSocket() socket: Socket) {

konst bruker = avventedette.chatsService.getUserFromSocket (socket)
dette.server.sockets.emit('motta_melding', {
beskjed,
bruker
});
}
}

Du kan referere til filene som er involvert i autentiseringssystemet ovenfor i GitHub-depot for å se de komplette kodene (inkludert import), for en bedre forståelse av implementeringen.

Vedvarende chatter til databasen

For at brukere skal se meldingsloggen deres, trenger du et skjema for å lagre meldinger. Opprett en ny fil kalt melding.skjema.ts og lim inn koden nedenfor i den (husk å importere din brukerskjema eller sjekk ut depotet for en).

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

eksport type MessageDocument = Melding og dokument;

@Skjema({
tilJSON: {
getters: ekte,
virtuelle: ekte,
},
tidsstempler: ekte,
})
eksportklasseBeskjed{
@Rekvisitt({ nødvendig: ekte, unik: ekte })
melding: streng

@Rekvisitt({ type: mangust. Skjema. Typer. ObjectId, ref: 'Bruker' })
bruker: Bruker
}

konst MessageSchema = SchemaFactory.createForClass (Message)

eksport { MessageSchema };

Nedenfor er en implementering av tjenester for å lage en ny melding og få inn alle meldinger chats.service.ts.

import { Message, MessageDocument } fra'./melding.skjema'; 
import { Stikkontakt } fra'socket.io';
import { AuthService } fra'./../auth/auth.service';
import { Injiserbar } fra'@nestjs/common';
import { WsException } fra'@nestjs/websockets';
import { InjectModel } fra'@nestjs/mongoose';
import { Modell } fra"mangus";
import { MessageDto } fra'./dto/melding.dto';

@Injiserbar()
eksportklasseChatsService{
konstruktør(privat authService: AuthService, @InjectModel (Message.name) privat meldingModel: Modell) {}
...
asynkron createMessage (melding: MessageDto, bruker-ID: string) {
konst newMessage = nydette.messageModel({...message, userId})
avvente newMessage.save
komme tilbake ny melding
}
asynkron getAllMessages() {
komme tilbakedette.messageModel.find().populate('bruker')
}
}

De MessageDto er implementert i en melding.dto.ts fil i dto mappe i chatter katalog. Du kan også finne den i depotet.

Du må legge til beskjed modell og skjema til listen over importer i chats.module.ts.

import { Message, MessageSchema } fra'./melding.skjema';
import { Modul } fra'@nestjs/common';
import { ChatGateway } fra'./chats.gateway';
import { ChatsService } fra'./chats.service';
import { MongooseModule } fra'@nestjs/mongoose';

@Module({
importerer: [MongooseModule.forFeature([
{ Navn: Message.name, skjema: MessageSchema }
])],
kontrollere: [],
leverandører: [ChatsService, ChatGateway]
})
eksportklasseChatsModule{}

Til slutt, den få_alle_meldinger hendelsesbehandler legges til ChatGateway klasse i chat.gateway.ts som vist i følgende kode:

// importerer...

@WebSocketGateway()
eksportklasseChatGatewayredskaperOnGatewayConnection{
...

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

avventedette.chatsService.getUserFromSocket (socket)
konst meldinger = avventedette.chatsService.getAllMessages()

dette.server.sockets.emit('motta_melding', meldinger);

komme tilbake meldinger
}
}

Når en tilkoblet klient (bruker) sender ut få_alle_meldinger hendelsen, vil alle meldingene deres bli hentet, og når de sender ut sende melding, en melding opprettes og lagres i databasen, og sendes deretter til alle andre tilkoblede klienter.

Når du er ferdig med alle trinnene ovenfor, kan du starte applikasjonen med npm kjørestart: dev, og test den med en WebSocket-klient som Postman.

Bygge sanntidsapplikasjoner med NestJS

Selv om det finnes andre teknologier for å bygge sanntidssystemer, er WebSockets veldig populære og enkle å implementere i mange tilfeller, og de er det beste alternativet for chat-applikasjoner.

Sanntidsapplikasjoner er ikke bare begrenset til chatteapplikasjoner, andre eksempler inkluderer videostreaming eller ringeapplikasjoner og liveværapplikasjoner, og NestJS gir flott verktøy for å bygge sanntid apper.