Découvrez comment créer une API de chat en temps réel en tirant parti de la puissance de WebSockets à l'aide de NestJS.
NestJS est un framework populaire pour créer des applications côté serveur avec Node.js. Avec sa prise en charge de WebSockets, NestJS est bien adapté au développement d'applications de chat en temps réel.
Alors, que sont les WebSockets et comment pouvez-vous créer une application de chat en temps réel dans NestJS ?
Que sont les WebSockets?
Les WebSockets sont un protocole de communication persistante, en temps réel et bidirectionnelle entre un client et un serveur.
Contrairement à HTTP où une connexion est fermée lorsqu'un cycle de requête est terminé entre le client et le serveur, une connexion WebSocket est maintenue ouverte et ne se ferme pas même après qu'une réponse a été renvoyée pendant un demande.
L'image ci-dessous est une visualisation du fonctionnement d'une communication WebSocket entre un serveur et un client :
Pour établir une communication bidirectionnelle, le client envoie une demande de prise de contact WebSocket au serveur. Les en-têtes de requête contiennent une clé WebSocket sécurisée (
Sec-WebSocket-Key), Et un Mise à niveau: WebSocket en-tête qui, avec le Connexion: mise à niveau L'en-tête indique au serveur de mettre à niveau le protocole HTTP vers WebSocket et de maintenir la connexion ouverte. Apprendre sur WebSocket en JavaScript permet de mieux comprendre le concept.Création d'une API de chat en temps réel à l'aide du module NestJS WebSocket
Node.js fournit deux implémentations majeures de WebSockets. Le premier est ws qui implémente des WebSockets nus. Et le second est socket.io, qui fournit davantage de fonctionnalités de haut niveau.
NestJS a des modules pour les deux socket.io et ws. Cet article utilise le socket.io module pour les fonctionnalités WebSocket de l'exemple d'application.
Le code utilisé dans ce projet est disponible dans un Référentiel GitHub. Il est recommandé de le cloner localement pour mieux comprendre la structure du répertoire et voir comment tous les codes interagissent les uns avec les autres.
Configuration et installation du projet
Ouvrez votre terminal et générez une nouvelle application NestJS à l'aide de nid nouveau commande (par ex. imbriquer une nouvelle application de chat). La commande génère un nouveau répertoire qui contient les fichiers du projet. Vous êtes maintenant prêt à démarrer le processus de développement.
Configurer une connexion MongoDB
Pour conserver les messages de chat dans l'application, vous avez besoin d'une base de données. Cet article utilise la base de données MongoDB pour notre application NestJS, et le moyen le plus simple de commencer à courir est de configurer un cluster MongoDB dans le cloud et obtenez votre URL MongoDB. Copiez l'URL et stockez-la en tant que MONGO_URI variables dans votre .env déposer.
Vous auriez également besoin de Mongoose plus tard lorsque vous ferez des requêtes à MongoDB. Installez-le en exécutant npm installer la mangouste dans votre borne.
Dans le src dossier, créez un fichier appelé mongo.config.ts et collez-y le code suivant.
importer { enregistrerAs } depuis'@nestjs/config';
/**
* Configuration de la connexion à la base de données Mongo
*/
exporterdéfaut s'inscrireAs('mongodb', () => {
constante { MONGO_URI } = process.env; // à partir du fichier .env
retour {
uri :`${MONGO_URI}`,
};
});
Tes projets main.ts le fichier devrait ressembler à ceci :
importer {NestFactory} depuis'@nestjs/core';
importer {Module d'application} depuis'./app.module';
importer * comme cookieParser depuis'analyseur de cookies'
importer casque depuis'casque'
importer { Enregistreur, ValidationPipe } depuis'@nestjs/commun';
importer { setupSwagger } depuis'./utils/swagger';
importer { HttpExceptionFilter } depuis'./filters/http-exception.filter';asynchronefonctionamorcer() {
constante application = attendre NestFactory.create (AppModule, { cors: vrai });
app.enableCors({
origine: '*',
crédits: vrai
})
app.use (cookieParser())
app.useGlobalPipes(
nouveau ValidationPipe({
liste blanche: vrai
})
)
constante enregistreur = nouveau Enregistreur('Principal')app.setGlobalPrefix('API/v1')
app.useGlobalFilters(nouveau HttpExceptionFilter());setupSwagger (application)
app.use (casque())attendre app.listen (AppModule.port)
// journaliser les documents
constante baseUrl = AppModule.getBaseUrl (application)
constante URL = `http://${baseUrl}:${AppModule.port}`
logger.log(`Documentation API disponible sur ${url}/docs`);
}
amorcer();
Construire le module de chat
Pour commencer avec la fonctionnalité de chat en temps réel, la première étape consiste à installer les packages NestJS WebSockets. Cela peut être fait en exécutant la commande suivante dans le terminal.
npm install @nestjs/websockets @nestjs/platform-socket.io @types/socket.io
Après avoir installé les packages, vous devez générer le module de chat en exécutant les commandes suivantes
chats du module Nest G
chat du contrôleur nest g
chat du service nest g
Une fois la génération du module terminée, l'étape suivante consiste à créer une connexion WebSockets dans NestJS. Créer un chat.passerelle.ts fichier à l'intérieur du chats dossier, c'est là que la passerelle qui envoie et reçoit les messages est implémentée.
Collez le code suivant dans chat.passerelle.ts.
importer {
Corps du message,
S'abonnerMessage,
passerelle WebSocket,
WebSocketServer,
} depuis'@nestjs/websockets';
importer { Serveur } depuis'socket.io';
@WebSocketGateway()
exporterclasseChatGateway{
@WebSocketServer()
serveur: Serveur ;
// écoute les événements send_message
@SubscribeMessage('envoyer le message')
listenForMessages(@MessageBody() message: chaîne) {
ce.server.sockets.emit('recevoir_message', message);
}
}
Authentification des utilisateurs connectés
L'authentification est une partie essentielle des applications Web, et ce n'est pas différent pour une application de chat. La fonction d'authentification des connexions client au socket se trouve dans chats.service.ts comme montré ici :
@Injectable()
exporterclasseChatsService{
constructeur(service d'authentification privé: service d'authentification) {}asynchrone getUserFromSocket (socket: Socket) {
laisser auth_token = socket.handshake.headers.authorization ;
// récupère le jeton lui-même sans "Bearer"
auth_token = auth_token.split(' ')[1];constante utilisateur = ce.authService.getUserFromAuthenticationToken(
auth_token
);
si (!utilisateur) {
lancernouveau WsException('Les informations d'identification invalides.');
}
retour utilisateur;
}
}
Le getUserFromSocket méthode utilise getUserFromAuthenticationToken pour obtenir l'utilisateur actuellement connecté à partir du jeton JWT en extrayant le jeton Bearer. Le getUserFromAuthenticationToken fonction est implémentée dans le auth.service.ts fichier comme indiqué ici :
public asynchrone getUserFromAuthenticationToken (jeton: chaîne) {
constante charge utile: JwtPayload = ce.jwtService.verify (jeton, {
secret: ce.configService.get('JWT_ACCESS_TOKEN_SECRET'),
});constante userId = charge utile.sub
si (ID de l'utilisateur) {
retource.usersService.findById (ID utilisateur) ;
}
}
La socket actuelle est passée en paramètre à getUserFromSocket quand le poignéeConnexion méthode de ChatGateway met en œuvre le OnGatewayConnection interface. Cela permet de recevoir des messages et des informations sur l'utilisateur actuellement connecté.
Le code ci-dessous le démontre :
// chat.passerelle.ts
@WebSocketGateway()
exporterclasseChatGatewaymet en oeuvreOnGatewayConnection{
@WebSocketServer()
serveur: Serveur ;constructeur(chats privés Service: ChatsService) {}
asynchrone poignéeConnexion (socket: Socket) {
attendrece.chatsService.getUserFromSocket (socket)
}@SubscribeMessage('envoyer le message')
asynchrone listenForMessages(@MessageBody() message: chaîne, @ConnectedSocket() socket: Socket) {
constante utilisateur = attendrece.chatsService.getUserFromSocket (socket)
ce.server.sockets.emit('recevoir_message', {
message,
utilisateur
});
}
}
Vous pouvez référencer les fichiers impliqués dans le système d'authentification ci-dessus dans le Référentiel GitHub pour voir les codes complets (y compris les importations), pour une meilleure compréhension de la mise en œuvre.
Chats persistants dans la base de données
Pour que les utilisateurs puissent voir leur historique de messagerie, vous avez besoin d'un schéma pour stocker les messages. Créez un nouveau fichier appelé message.schema.ts et collez-y le code ci-dessous (n'oubliez pas d'importer votre schéma utilisateur ou consultez le référentiel pour un).
importer { Utilisateur } depuis'./../users/schemas/user.schema';
importer { Prop, Schema, SchemaFactory } depuis"@nestjs/mangouste";
importer mangouste, { Document } depuis"mangouste";exporter tapez MessageDocument = Message & Document ;
@Schéma({
versJSON: {
getters: vrai,
virtuels: vrai,
},
horodatage: vrai,
})
exporterclasseMessage{
@Soutenir({ requis: vrai, unique: vrai })
message: chaîne@Soutenir({ taper: mangouste. Schéma. Les types. ID d'objet, réf: 'Utilisateur' })
utilisateur: Utilisateur
}constante MessageSchema = SchemaFactory.createForClass (Message)
exporter { MessageSchema } ;
Vous trouverez ci-dessous une implémentation de services pour créer un nouveau message et obtenir tous les messages dans chats.service.ts.
importer { Message, MessageDocument } depuis'./message.schéma';
importer { Prise } depuis'socket.io';
importer { AuthService } depuis'./../auth/auth.service';
importer { Injectables } depuis'@nestjs/commun';
importer { WsException } depuis'@nestjs/websockets';
importer { InjectModel } depuis'@nestjs/mangouste';
importer { Modèle } depuis'mangouste';
importer { MessageDto } depuis'./dto/message.dto';
@Injectable()
exporterclasseChatsService{
constructeur(privé authService: AuthService, @InjectModel (Message.name) message privéModèle: modèle) {}
...
asynchrone createMessage (message: MessageDto, ID de l'utilisateur: chaîne) {
constante nouveauMessage = nouveauce.messageModel({...message, userId})
attendre nouveauMessage.save
retour nouveau message
}
asynchrone getAllMessages() {
retource.messageModel.find().populate('utilisateur')
}
}
Le MessageDà est mis en œuvre dans un message.dto.ts dossier dans le dto dossier dans le chats annuaire. Vous pouvez également le trouver dans le référentiel.
Vous devez ajouter le message modèle et schéma à la liste des importations dans chats.module.ts.
importer { Message, Schéma de message } depuis'./message.schéma';
importer { Module } depuis'@nestjs/commun';
importer { ChatGateway } depuis'./chats.passerelle';
importer { ChatsService } depuis'./chats.service';
importer {Module Mongoose} depuis'@nestjs/mangouste';
@Module({
importe: [MongooseModule.forFeature([
{ nom: Nom.du.message, schéma: MessageSchema }
])],
contrôleurs: [],
fournisseurs: [ChatsService, ChatGateway]
})
exporterclasseModuleChats{}
Finalement, le get_all_messages gestionnaire d'événements est ajouté au ChatGateway classe dans chat.passerelle.ts comme on le voit dans le code suivant :
// importe...
@WebSocketGateway()
exporterclasseChatGatewaymet en oeuvreOnGatewayConnection{
...@SubscribeMessage('obtenir_tous_les_messages')
asynchrone getAllMessages(@ConnectedSocket() socket: Socket) {attendrece.chatsService.getUserFromSocket (socket)
constante message = attendrece.chatsService.getAllMessages()ce.server.sockets.emit('recevoir_message', messages);
retour messages
}
}
Lorsqu'un client (utilisateur) connecté émet le message get_all_messages événement, tous leurs messages seront récupérés, et lorsqu'ils émettront envoyer le message, un message est créé et stocké dans la base de données, puis envoyé à tous les autres clients connectés.
Une fois toutes les étapes ci-dessus terminées, vous pouvez démarrer votre application en utilisant démarrage de l'exécution npm: dev, et testez-le avec un client WebSocket tel que Postman.
Créer des applications en temps réel avec NestJS
Bien qu'il existe d'autres technologies pour créer des systèmes en temps réel, les WebSockets sont très populaires et faciles à mettre en œuvre dans de nombreux cas, et ils constituent la meilleure option pour les applications de chat.
Les applications en temps réel ne se limitent pas aux applications de chat, d'autres exemples incluent le streaming vidéo ou applications d'appel et applications météo en direct, et NestJS fournit d'excellents outils pour créer en temps réel applications.