DEV Community

azuli jerson
azuli jerson

Posted on

HTTP Websocket

How do I create an HTTP server and use websocket?

Top comments (1)

Collapse
 
kl_cage_a861d0e0fb04635ea profile image
Kl Cage

Claro! Vamos ajustar o projeto para que as alterações no banco de dados feitas no backend sejam informadas aos clientes conectados via WebSocket.

1. Configurando o Servidor HTTP e WebSocket

Primeiro, precisamos configurar o servidor HTTP e WebSocket. Vamos instalar os pacotes necessários e configurar os módulos do NestJS.

Instalando pacotes necessários

npm install --save @nestjs/websockets @nestjs/platform-socket.io socket.io
npm install --save @nestjs/typeorm typeorm mysql2
Enter fullscreen mode Exit fullscreen mode

Criando o Módulo WebSocket

Crie um módulo para o WebSocket:

nest generate module chat
Enter fullscreen mode Exit fullscreen mode

Criando o Gateway WebSocket

Crie um gateway WebSocket dentro do módulo chat:

nest generate gateway chat/chat
Enter fullscreen mode Exit fullscreen mode

Edite o arquivo chat.gateway.ts para configurar o WebSocket:

import {
  WebSocketGateway,
  WebSocketServer,
  SubscribeMessage,
  MessageBody,
  OnGatewayInit,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { ChatService } from './chat.service';
import { CreateMessageDto } from './dto/create-message.dto';

@WebSocketGateway()
export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer() server: Server;

  constructor(private readonly chatService: ChatService) {}

  afterInit(server: Server) {
    console.log('WebSocket initialized');
  }

  handleConnection(client: Socket, ...args: any[]) {
    console.log(`Client connected: ${client.id}`);
  }

  handleDisconnect(client: Socket) {
    console.log(`Client disconnected: ${client.id}`);
  }

  @SubscribeMessage('sendMessage')
  async handleMessage(@MessageBody() createMessageDto: CreateMessageDto) {
    const message = await this.chatService.createMessage(createMessageDto);
    this.server.emit('receiveMessage', message);
    return message;
  }
}
Enter fullscreen mode Exit fullscreen mode

Criando o Serviço de Chat

Crie um serviço para lidar com as mensagens de chat:

nest generate service chat/chat
Enter fullscreen mode Exit fullscreen mode

Edite o arquivo chat.service.ts:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Message } from './entities/message.entity';
import { CreateMessageDto } from './dto/create-message.dto';
import { ChatGateway } from './chat.gateway';

@Injectable()
export class ChatService {
  constructor(
    @InjectRepository(Message)
    private readonly messageRepository: Repository<Message>,
    private readonly chatGateway: ChatGateway,
  ) {}

  async createMessage(createMessageDto: CreateMessageDto): Promise<Message> {
    const message = this.messageRepository.create(createMessageDto);
    const savedMessage = await this.messageRepository.save(message);
    // Emitir a mensagem salva para todos os clientes conectados
    this.chatGateway.server.emit('receiveMessage', savedMessage);
    return savedMessage;
  }

  async updateOrderStatus(status: string) {
    // Lógica para atualizar o status do pedido no banco de dados
    // Exemplo: await this.orderRepository.update(orderId, { status });
    this.chatGateway.server.emit('orderStatusUpdated', { status });
  }

  async findAllMessages(): Promise<Message[]> {
    return await this.messageRepository.find();
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Configurando o Banco de Dados

Criando a Entidade de Mensagem

Crie a entidade Message:

nest generate entity chat/message
Enter fullscreen mode Exit fullscreen mode

Edite o arquivo message.entity.ts:

import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn } from 'typeorm';

@Entity()
export class Message {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  user: string;

  @Column()
  content: string;

  @CreateDateColumn()
  createdAt: Date;
}
Enter fullscreen mode Exit fullscreen mode

Criando DTO para Mensagem

Crie o DTO CreateMessageDto:

nest generate class chat/dto/create-message.dto --no-spec
Enter fullscreen mode Exit fullscreen mode

Edite o arquivo create-message.dto.ts:

export class CreateMessageDto {
  user: string;
  content: string;
}
Enter fullscreen mode Exit fullscreen mode

Configurando o TypeORM

Edite o arquivo app.module.ts para configurar o TypeORM:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ChatModule } from './chat/chat.module';
import { Message } from './chat/entities/message.entity';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'password',
      database: 'chat_db',
      entities: [Message],
      synchronize: true,
    }),
    ChatModule,
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

3. Criando o Frontend

Para criar uma interface simples onde o usuário pode enviar mensagens e ver o status atualizado, vamos usar HTML, CSS e JavaScript com o Socket.IO.

Crie um arquivo index.html na pasta public:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Chat Application</title>
  <script src="/socket.io/socket.io.js"></script>
</head>
<body>
  <div>
    <h2>Chat</h2>
    <div id="messages"></div>
    <input id="user" type="text" placeholder="Your name">
    <input id="message" type="text" placeholder="Your message">
    <button onclick="sendMessage()">Send</button>
  </div>
  <div>
    <h2>Order Status</h2>
    <div id="orderStatus"></div>
  </div>

  <script>
    const socket = io();

    socket.on('receiveMessage', function (message) {
      const messagesDiv = document.getElementById('messages');
      messagesDiv.innerHTML += `<p><strong>${message.user}:</strong> ${message.content}</p>`;
    });

    socket.on('orderStatusUpdated', function (data) {
      const orderStatusDiv = document.getElementById('orderStatus');
      orderStatusDiv.innerHTML = `<p>Order Status: ${data.status}</p>`;
    });

    function sendMessage() {
      const user = document.getElementById('user').value;
      const content = document.getElementById('message').value;
      socket.emit('sendMessage', { user, content });
    }
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

4. Servindo o Frontend com o NestJS

Crie um controlador para servir o arquivo HTML:

nest generate controller app
Enter fullscreen mode Exit fullscreen mode

Edite o arquivo app.controller.ts:

import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
import { join } from 'path';

@Controller()
export class AppController {
  @Get()
  getHtml(@Res() res: Response) {
    res.sendFile(join(__dirname, '..', 'public', 'index.html'));
  }
}
Enter fullscreen mode Exit fullscreen mode

Certifique-se de que o servidor NestJS está configurado para servir arquivos estáticos. Edite o arquivo main.ts:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.useStaticAssets(join(__dirname, '..', 'public'));
  await app.listen(3000);
}
bootstrap();
Enter fullscreen mode Exit fullscreen mode

5. Atualizando o Status de Pedido no Backend

Para atualizar o status do pedido e notificar todos os clientes conectados, adicione um método no serviço que trata da lógica de negócios do pedido. Vamos supor que você tenha um serviço de pedidos. Aqui está um exemplo:

Criando o Serviço de Pedidos

Crie um serviço para lidar com os pedidos:

nest generate service order/order
Enter fullscreen mode Exit fullscreen mode

Edite o arquivo order.service.ts:

import { Injectable } from '@nestjs/common';
import { ChatService } from '../chat/chat.service';

@Injectable()
export class OrderService {
  constructor(private readonly chatService: ChatService) {}

  async updateOrderStatus(status: string) {
    // Lógica para atualizar o status do pedido no banco de dados
    // Exemplo: await this.orderRepository.update(orderId, { status });
    // Notificar todos os clientes conectados sobre a atualização do status do pedido
    this.chatService.updateOrderStatus(status);
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusão

Com essas configurações, você terá um servidor HTTP e WebSocket funcionando no NestJS, permitindo enviar mensagens, salvá-las no banco de dados e atualizar o status de um pedido, tudo sendo refletido na interface do usuário. Certifique-se de que o banco de dados MySQL esteja configurado corretamente e em execução.

Esse exemplo cobre a criação de mensagens de chat e notificação de status de pedidos alterados no backend para todos os clientes conectados via WebSocket.