Naučite kako izgraditi API za chat u stvarnom vremenu koristeći snagu WebSockets koristeći NestJS.

NestJS je popularan okvir za izgradnju aplikacija na strani poslužitelja s Node.js. Uz podršku za WebSockets, NestJS je vrlo prikladan za razvoj aplikacija za chat u stvarnom vremenu.

Dakle, što su WebSockets i kako možete izgraditi aplikaciju za chat u stvarnom vremenu u NestJS-u?

Što su WebSockets?

WebSockets su protokol za postojanu dvosmjernu komunikaciju u stvarnom vremenu između klijenta i poslužitelja.

Za razliku od HTTP-a gdje se veza zatvara kada se završi ciklus zahtjeva između klijenta i poslužitelja, WebSocket veza ostaje otvorena i ne zatvara se čak ni nakon što je vraćen odgovor za a zahtjev.

Slika ispod je vizualizacija kako funkcionira WebSocket komunikacija između poslužitelja i klijenta:

Za uspostavljanje dvosmjerne komunikacije, klijent poslužitelju šalje WebSocket zahtjev za rukovanje. Zaglavlja zahtjeva sadrže sigurni WebSocket ključ (Sec-WebSocket-Key), i an Nadogradnja: WebSocket

instagram viewer
zaglavlje koje zajedno s Veza: Nadogradnja zaglavlje govori poslužitelju da nadogradi protokol s HTTP-a na WebSocket i zadrži vezu otvorenom. Učenje o WebSockets u JavaScriptu pomaže još boljem razumijevanju koncepta.

Izrada API-ja za chat u stvarnom vremenu pomoću NestJS WebSocket modula

Node.js pruža dvije glavne implementacije WebSocketsa. Prvi je ws koji implementira gole WebSockets. A drugi je utičnica.io, koji pruža značajke više razine.

NestJS ima module za oboje utičnica.io i ws. Ovaj članak koristi utičnica.io modul za WebSocket značajke uzorka aplikacije.

Kod korišten u ovom projektu dostupan je u a GitHub spremište. Preporuča se da ga lokalno klonirate kako biste bolje razumjeli strukturu direktorija i vidjeli kako svi kodovi međusobno djeluju.

Postavljanje i instalacija projekta

Otvorite svoj terminal i generirajte novu NestJS aplikaciju pomoću gnijezdo novo naredba (npr. nest nova aplikacija za chat). Naredba generira novi direktorij koji sadrži datoteke projekta. Sada ste spremni za početak procesa razvoja.

Postavite MongoDB vezu

Da biste zadržali chat poruke u aplikaciji, potrebna vam je baza podataka. Ovaj članak koristi baza podataka MongoDB za našu aplikaciju NestJS, a najlakši način za trčanje je postaviti MongoDB klaster u oblaku i dobijte svoj MongoDB URL. Kopirajte URL i pohranite ga kao MONGO_URI varijabla u vašem .env datoteka.

Mongoose bi vam također trebao kasnije kada budete postavljali upite MongoDB-u. Instalirajte ga pokretanjem npm instalirajte mongoose u vašem terminalu.

u src mapu, stvorite datoteku pod nazivom mongo.config.ts i zalijepite sljedeći kod u njega.

uvoz { registerAs } iz'@nestjs/config';

/**
* Konfiguracija veze Mongo baze podataka
*/

izvozzadano registerAs('mongodb', () => {
konst {MONGO_URI} = process.env; // iz .env datoteke
povratak {
uri:`${MONGO_URI}`,
};
});

Vaš projekt glavni.ts datoteka bi trebala izgledati ovako:

uvoz { NestFactory } iz'@nestjs/core';
uvoz { AppModule } iz'./app.modul';
uvoz * kao cookieParser iz'cookie-parser'
uvoz kaciga iz'kaciga'
uvoz {Logger, ValidationPipe} iz'@nestjs/common';
uvoz { setupSwagger } iz'./utils/swagger';
uvoz {HttpExceptionFilter} iz'./filters/http-exception.filter';

asinkronifunkcijabootstrap() {
konst aplikacija = čekati NestFactory.create (AppModule, { cors: pravi });
app.enableCors({
podrijetlo: '*',
vjerodajnice: pravi
})
app.use (cookieParser())
app.useGlobalPipes(
novi ValidationPipe({
popis dopuštenih: pravi
})
)
konst drvosječa = novi Drvosječa('Glavni')

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

setupSwagger (aplikacija)
app.use (kaciga())

čekati app.listen (AppModule.port)

// zapisnik dokumenata
konst baseUrl = AppModule.getBaseUrl (aplikacija)
konst url = `http://${baseUrl}:${AppModule.port}`
logger.log(`API dokumentacija dostupna na ${url}/docs`);
}
bootstrap();

Izrada modula za chat

Da biste započeli sa značajkom chata u stvarnom vremenu, prvi korak je instaliranje paketa NestJS WebSockets. To se može učiniti pokretanjem sljedeće naredbe u terminalu.

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

Nakon instaliranja paketa, morate generirati chat modul pokretanjem sljedećih naredbi

nest g modul chatovi
nest g kontroler chatovi
nest g servisni razgovori

Nakon što završite s generiranjem modula, sljedeći korak je stvaranje WebSockets veze u NestJS-u. Stvoriti chat.gateway.ts datoteka unutar razgovori mapu, ovdje je implementiran gateway koji šalje i prima poruke.

Zalijepite sljedeći kod u chat.gateway.ts.

uvoz {
Tijelo poruke,
Pretplati se Poruka,
WebSocketGateway,
WebSocketServer,
} iz'@nestjs/websockets';
uvoz { Poslužitelj } iz'socket.io';

@WebSocketGateway()
izvozrazredaChatGateway{
@WebSocketServer()
poslužitelj: poslužitelj;
// slušanje događaja send_message
@SubscribeMessage('Pošalji poruku')
listenForMessages(@MessageBody() poruka: niz) {
ovaj.server.sockets.emit('primi_poruku', poruka);
}
}

Provjera autentičnosti povezanih korisnika

Autentifikacija je bitan dio web aplikacija, a nije drugačija ni za aplikaciju za chat. Funkcija za provjeru autentičnosti veza klijenta s utičnicom nalazi se u chatovi.service.ts kao što je prikazano ovdje:

@Injectable()
izvozrazredaChatsService{
konstruktor(privatni authService: AuthService) {}

asinkroni getUserFromSocket (utičnica: utičnica) {
neka auth_token = socket.handshake.headers.authorization;
// dobiti sam token bez "Nosioca"
auth_token = auth_token.split(' ')[1];

konst korisnik = ovaj.authService.getUserFromAuthenticationToken(
autent_token
);

ako (!korisnik) {
bacanjenovi WsException('Nevažeće vjerodajnice.');
}
povratak korisnik;
}
}

The getUserFromSocket metoda koristi getUserFromAuthenticationToken da dobijete trenutno prijavljenog korisnika iz JWT tokena izdvajanjem Bearer tokena. The getUserFromAuthenticationToken funkcija je implementirana u auth.service.ts datoteku kao što je prikazano ovdje:

javnost asinkroni getUserFromAuthenticationToken (token: niz) {
konst korisni teret: JwtPayload = ovaj.jwtService.verify (token, {
tajna: ovaj.configService.get('JWT_ACCESS_TOKEN_SECRET'),
});

konst userId = korisni teret.sub

ako (userId) {
povratakovaj.usersService.findById (userId);
}
}

Trenutačna utičnica se prosljeđuje kao parametar getUserFromSocket kada handleConnection metoda od ChatGateway provodi OnGatewayConnection sučelje. To omogućuje primanje poruka i informacija o trenutno spojenom korisniku.

Kod u nastavku to pokazuje:

// chat.gateway.ts
@WebSocketGateway()
izvozrazredaChatGatewayoruđaOnGatewayConnection{
@WebSocketServer()
poslužitelj: poslužitelj;

konstruktor(privatni chatsService: ChatsService) {}

asinkroni handleConnection (utičnica: utičnica) {
čekatiovaj.chatsService.getUserFromSocket (utičnica)
}

@SubscribeMessage('Pošalji poruku')
asinkroni listenForMessages(@MessageBody() poruka: niz, @ConnectedSocket() utičnica: utičnica) {

konst korisnik = čekatiovaj.chatsService.getUserFromSocket (utičnica)
ovaj.server.sockets.emit('primi_poruku', {
poruka,
korisnik
});
}
}

Možete referencirati datoteke uključene u sustav provjere autentičnosti iznad u GitHub spremište da biste vidjeli kompletne kodove (uključujući uvoze), radi boljeg razumijevanja implementacije.

Trajni razgovori s bazom podataka

Da bi korisnici vidjeli svoju povijest slanja poruka, potrebna vam je shema za pohranu poruka. Napravite novu datoteku pod nazivom poruka.shema.ts i u njega zalijepite donji kod (ne zaboravite uvesti svoj korisnička shema ili provjerite spremište za jedan).

uvoz { Korisnik } iz'./../users/schemas/user.schema';
uvoz {Prop, Schema, SchemaFactory} iz"@nestjs/mungos";
uvoz mungos, { Dokument } iz"mungos";

izvoz tip MessageDocument = Poruka & dokument;

@Shema({
toJSON: {
primatelji: pravi,
virtualno: pravi,
},
vremenske oznake: pravi,
})
izvozrazredaPoruka{
@Prop({ potreban: pravi, jedinstvena: pravi })
poruka: niz

@Prop({ tip: mungos. Shema. Vrste. ID objekta, ref: 'Korisnik' })
korisnik: korisnik
}

konst MessageSchema = SchemaFactory.createForClass (poruka)

izvoz {Shema poruke};

Ispod je implementacija usluga za stvaranje nove poruke i primanje svih poruka chatovi.service.ts.

uvoz { Poruka, MessageDocument } iz'./message.schema'; 
uvoz { utičnica } iz'socket.io';
uvoz {AuthService} iz'./../auth/auth.service';
uvoz { Injekcioni } iz'@nestjs/common';
uvoz {WsException} iz'@nestjs/websockets';
uvoz {InjectModel} iz'@nestjs/mungos';
uvoz { Model } iz'mungos';
uvoz { MessageDto } iz'./dto/message.dto';

@Injectable()
izvozrazredaChatsService{
konstruktor(privatni authService: AuthService, @InjectModel (Message.name) privatna porukaModel: Model) {}
...
asinkroni createMessage (poruka: MessageDto, userId: niz) {
konst nova poruka = noviovaj.messageModel({...poruka, userId})
čekati novaPoruka.spremi
povratak nova poruka
}
asinkroni getAllMessages() {
povratakovaj.messageModel.find().populate('korisnik')
}
}

The PorukaDto implementira se u a poruka.dto.ts datoteka u dto mapu u razgovori imenik. Možete ga pronaći i u repozitoriju.

Morate dodati poruka model i shema na popis uvoza u razgovori.modul.ts.

uvoz { Poruka, Shema poruke } iz'./message.schema';
uvoz { Modul } iz'@nestjs/common';
uvoz {ChatGateway} iz'./chats.gateway';
uvoz { ChatsService } iz'./chats.service';
uvoz { MongooseModule } iz'@nestjs/mungos';

@Modul({
uvozi: [MongooseModule.forFeature([
{ Ime: ime.poruke, shema: Shema poruke }
])],
kontroleri: [],
pružatelji usluga: [ChatsService, ChatGateway]
})
izvozrazredaChatsModule{}

Konačno, dobiti_sve_poruke rukovatelj događajima dodan je u ChatGateway razred u chat.gateway.ts kao što se vidi u sljedećem kodu:

// uvozi...

@WebSocketGateway()
izvozrazredaChatGatewayoruđaOnGatewayConnection{
...

@SubscribeMessage('dobi_sve_poruke')
asinkroni getAllMessages(@ConnectedSocket() utičnica: utičnica) {

čekatiovaj.chatsService.getUserFromSocket (utičnica)
konst poruke = čekatiovaj.chatsService.getAllMessages()

ovaj.server.sockets.emit('primi_poruku', poruke);

povratak poruke
}
}

Kada povezani klijent (korisnik) emitira dobiti_sve_poruke događaja, sve njihove poruke će biti dohvaćene, a kada emitiraju Pošalji poruku, poruka se kreira i pohranjuje u bazu podataka, a zatim šalje svim drugim povezanim klijentima.

Kada završite sa svim gornjim koracima, možete pokrenuti svoju aplikaciju koristeći npm pokrenuti početak: dev, i testirajte ga s WebSocket klijentom kao što je Postman.

Izrada aplikacija u stvarnom vremenu s NestJS-om

Iako postoje druge tehnologije za izgradnju sustava u stvarnom vremenu, WebSockets su vrlo popularni i laki za implementaciju u mnogim slučajevima, a najbolja su opcija za chat aplikacije.

Aplikacije u stvarnom vremenu nisu ograničene samo na aplikacije za chat, drugi primjeri uključuju video streaming ili aplikacije za pozivanje i aplikacije za vremensku prognozu uživo, a NestJS pruža izvrsne alate za izgradnju u stvarnom vremenu aplikacije.