{"id":19076104,"url":"https://github.com/gapur/nest-chat-app","last_synced_at":"2025-09-07T17:32:19.616Z","repository":{"id":219600109,"uuid":"749203191","full_name":"Gapur/nest-chat-app","owner":"Gapur","description":"💬 Build a Real-time Chat App Using NestJS","archived":false,"fork":false,"pushed_at":"2024-02-07T21:02:53.000Z","size":725,"stargazers_count":10,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-09T01:57:00.026Z","etag":null,"topics":["backend","chat","nestjs","react","typescript","websockets"],"latest_commit_sha":null,"homepage":"https://medium.com/gitconnected/build-a-real-time-chat-app-using-nestjs-d57da4d35793","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Gapur.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-01-27T21:41:52.000Z","updated_at":"2024-10-06T05:32:24.000Z","dependencies_parsed_at":"2024-02-07T21:23:45.216Z","dependency_job_id":"818ca896-a517-43ea-b066-cbe585884b59","html_url":"https://github.com/Gapur/nest-chat-app","commit_stats":null,"previous_names":["gapur/nest-chat-app"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gapur%2Fnest-chat-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gapur%2Fnest-chat-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gapur%2Fnest-chat-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gapur%2Fnest-chat-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Gapur","download_url":"https://codeload.github.com/Gapur/nest-chat-app/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232235696,"owners_count":18492804,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","chat","nestjs","react","typescript","websockets"],"created_at":"2024-11-09T01:57:03.726Z","updated_at":"2025-01-02T18:19:09.026Z","avatar_url":"https://github.com/Gapur.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"http://nestjs.com/\" target=\"blank\"\u003e\u003cimg src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Real-time Chat App Using NestJS and Websockets\n\nI often find that communication between the client and server occurs using real-time or traditional REST APIs. However, in this article I would like to focus on the real time API — what it is and how it works. To understand this better, we will create a real-time chat app using NestJS and WebSockets.\n\n## Getting Started\n\n1. Clone this repository\n```\ngit clone git@github.com:Gapur/nest-chat-app.git\n```\n2. Install dependencies\n```\nnpm install\n```\n3. Launch app\n```\nnpm run start # for npm\n```\n\n## What is the Real-time API?\n\nThe real-time API is a communication between a client and a server that exchanges data in real time. They are usually based on WebSockets. If you are not familiar with WebSockets, it is a protocol that allows real-time communication between a client and server over a single connection. In NestJS, we can implement it using two WebSockets frameworks such as socket.io and ws. In this project we will use socket.io because it is easier to use.\n\n## Setting Up the Project\n\nBefore we start, I would like to talk about the project structure. Since we will be implementing a chat between the client and the server, we need to create two subprojects:\n- client — web app in React\n- server — real-time app in NestJS\n\n## Creating Our Server\n\nTo manage with WebSockets in NestJS, we should use Gateways. This is a simple class annotated with the @WebSocketGateway() decorator which is used to pass data from client to server and server to client.\n\nWe will generate a ChatGateway in our server subproject using the following command:\n\n```\nnest generate gateway chat\n```\n\nIt will create a chat folder with chat.gateway.ts and chat.gateway.spec.ts files.\n\nThe ChatGateway class is annotated with the WebSocketGateway decorator and has a handleMessage method with a message event subscription decorator. So it will process the incoming message while passing data from the client.\n\n```ts\nimport { SubscribeMessage, WebSocketGateway } from '@nestjs/websockets';\n\n @WebSocketGateway()\n export class ChatGateway {\n   @SubscribeMessage('message') // subscribe to message events\n   handleMessage(client: any, payload: any): string {\n     return 'Hello world!'; // return the text\n   }\n }\n ```\n\nThe handleMessage method requires two parameters:\nclient — a platform-specific socket instance\npayload — the data received from the client\n\nHow can we send or emit a message from the client side? We can do it using the socket.io-client package:\n```\nsocket.emit('events', { name: 'Nest' });\n```\n\nWe can also process response data from the server:\n```\nsocket.emit('events', { name: 'Nest' }, (data) =\u003e console.log(data));\n```\n\nWe’ll talk more about it in the next chapter.\n\nIn the previous example, we simply returned data from the server to a specific client. Now let’s broadcast a message to all customers who have subscribed up for chat messages.\n\n```ts\nimport {\n  SubscribeMessage,\n  WebSocketGateway,\n  WebSocketServer,\n  MessageBody,\n} from '@nestjs/websockets';\nimport { Logger } from '@nestjs/common';\nimport { Server, Socket } from 'socket.io';\n\nimport { AddMessageDto } from './dto/add-message.dto';\n\n@WebSocketGateway({ cors: { origin: '*' } })\nexport class ChatGateway {\n  @WebSocketServer()\n  server: Server;\n\n  private logger = new Logger('ChatGateway');\n\n  @SubscribeMessage('chat') // subscribe to chat event messages\n  handleMessage(@MessageBody() payload: AddMessageDto): AddMessageDto {\n    this.logger.log(`Message received: ${payload.author} - ${payload.body}`);\n    this.server.emit('chat', payload); // broadbast a message to all clients\n    return payload; // return the same payload data\n  }\n}\n```\n\nAbove, to access the socket.io server, we used the WebSocketServer decorator to inject the socket.io server type into the server.\n\nLast, we’ll use two handy lifecycle hooks provided by Nest to show when a socket is connected or disconnected.\n\n```ts\n@WebSocketGateway({ cors: { origin: '*' } })\nexport class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {\n  ...\n  ...\n \n  // it will be handled when a client connects to the server\n  handleConnection(socket: Socket) {\n    this.logger.log(`Socket connected: ${socket.id}`);\n  }\n\n  // it will be handled when a client disconnects from the server\n  handleDisconnect(socket: Socket) {\n    this.logger.log(`Socket disconnected: ${socket.id}`);\n  }\n}\n```\n\nThe ChatGateway class has implemented two interfaces, OnGatewayConnection and OnGatewayDisconnect, provided from the `@nestjs/websockets` package.\n\nAlso we defined WebSocketGateway with { cors: { origin: ‘*’ } } configuration option to be available to all origins. We did for a purpose, but in practice it is not secure and should only be opened to trusted sources.\n\n## Creating Our Web Client\n\nNow we are going to implement on the client side sending and receiving messages from the server in real time. We’ll create chat.tsx component with the following code:\n\n```tsx\nimport { useState, useEffect } from \"react\";\nimport { io } from \"socket.io-client\";\n\nconst SystemMessage = {\n  id: 1,\n  body: \"Welcome to the Nest Chat app\",\n  author: \"Bot\",\n};\n\n// create a new socket instance with localhost URL\nconst socket = io('http://localhost:4000', { autoConnect: false });\n\nexport function Chat({ currentUser, onLogout }) {\n  const [inputValue, setInputValue] = useState(\"\");\n  const [messages, setMessages] = useState([SystemMessage]);\n\n  useEffect(() =\u003e {\n    socket.connect(); // connect to socket\n\n    socket.on(\"connect\", () =\u003e { // fire when we have connection\n      console.log(\"Socket connected\");\n    });\n\n    socket.on(\"disconnect\", () =\u003e { // fire when socked is disconnected\n      console.log(\"Socket disconnected\");\n    });\n\n    // listen chat event messages\n    socket.on(\"chat\", (newMessage) =\u003e {\n      console.log(\"New message added\", newMessage);\n      setMessages((previousMessages) =\u003e [...previousMessages, newMessage]);\n    });\n\n    // remove all event listeners\n    return () =\u003e {\n      socket.off(\"connect\");\n      socket.off(\"disconnect\");\n      socket.off(\"chat\");\n    };\n  }, []);\n\n  const handleSendMessage = (e) =\u003e {\n    if (e.key !== \"Enter\" || inputValue.trim().length === 0) return;\n\n    // send a message to the server\n    socket.emit(\"chat\", { author: currentUser, body: inputValue.trim() });\n    setInputValue(\"\");\n  };\n\n  const handleLogout = () =\u003e {\n    socket.disconnect(); // disconnect when we do logout\n    onLogout();\n  };\n\n  return (\n    \u003cdiv className=\"chat\"\u003e\n      \u003cdiv className=\"chat-header\"\u003e\n        \u003cspan\u003eNest Chat App\u003c/span\u003e\n        \u003cbutton className=\"button\" onClick={handleLogout}\u003e\n          Logout\n        \u003c/button\u003e\n      \u003c/div\u003e\n      \u003cdiv className=\"chat-message-list\"\u003e\n        {messages.map((message, idx) =\u003e (\n          \u003cdiv\n            key={idx}\n            className={`chat-message ${\n              currentUser === message.author ? \"outgoing\" : \"\"\n            }`}\n          \u003e\n            \u003cdiv className=\"chat-message-wrapper\"\u003e\n              \u003cspan className=\"chat-message-author\"\u003e{message.author}\u003c/span\u003e\n              \u003cdiv className=\"chat-message-bubble\"\u003e\n                \u003cspan className=\"chat-message-body\"\u003e{message.body}\u003c/span\u003e\n              \u003c/div\u003e\n            \u003c/div\u003e\n          \u003c/div\u003e\n        ))}\n      \u003c/div\u003e\n      \u003cdiv className=\"chat-composer\"\u003e\n        \u003cinput\n          className=\"chat-composer-input\"\n          placeholder=\"Type message here\"\n          value={inputValue}\n          onChange={(e) =\u003e setInputValue(e.target.value)}\n          onKeyDown={handleSendMessage}\n        /\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nWe created a new socket instance with the localhost URL and connected to the socket when rendering the component. And we removed all listeners when the component is unmounted.\n\n# Conclusion\n\nThanks for reading — I hope you found this piece useful. Happy coding!\n\n## Article on Medium\n\n[Build a Real-time Chat App Using NestJS](https://levelup.gitconnected.com/build-a-real-time-chat-app-using-nestjs-d57da4d35793)\n\n## How to contribute?\n\n1. Fork this repo\n2. Clone your fork\n3. Code 🤓\n4. Test your changes\n5. Submit a PR!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgapur%2Fnest-chat-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgapur%2Fnest-chat-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgapur%2Fnest-chat-app/lists"}