Online chat room with Node.js
Tags: javascript, webdev, beginners, programming
Published: 2023-04-09 05:46:07

## Introduction
In this blog post, we will discuss how to build a simple online chat application using Node.js, Express.js, and MySQL. We will cover the technologies used, the software created, and the internal logic and structure of the code.

The chat application we will build supports user registration, login, and basic chat room functionalities such as creating, joining, and leaving chat rooms.
the full code is on github: [https://github.com/Henryshi101/online_chat.git]


## Technologies Used:

1. Node.js:
A JavaScript runtime built on Chrome's V8 JavaScript engine, allowing us to run JavaScript on the server-side.
2. Express: 
A fast, unopinionated, minimalist web framework for Node.js that helps us create APIs.
3. MySQL: 
A popular open-source relational database management system (RDBMS) used to store the data.
4. Sequelize: 
A promise-based Node.js ORM (Object-Relational Mapping) for MySQL that allows us to interact with the database using JavaScript objects and methods.
5. Basic HTML, CSS and JavaScript:
Use to create Frontend.


## Structure

Here is the overall structure

![Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u18kvy2x4oab7kiquy8c.png)





## Backend Structure



### Database schema:
I have four tables in our MySQL database: users, chatrooms, chatroom_members, and messages. The schema for these tables can be found in the SQL code provided. Each table has its own primary key and appropriate foreign key relationships to ensure data integrity. To save some words, the structure is available on my github repo.

### Creating the Express API: server.js

I use Express to create an API with different routes for user registration, login, chat room management, and message management. The routes can be found in the routes.js file. I also use the cors package to enable Cross-Origin Resource Sharing, which allows the front-end application to communicate with the API.
```
const express = require('express');
const bodyParser = require('body-parser');
const routes = require('./backend/routes');
const cors = require('cors'); // Import the cors package

const app = express();
const PORT = process.env.PORT || 5000;

app.use(cors()); // Use cors middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.use('/api', routes);

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

```

### Sequelize:
In the db.js file, I set up Sequelize to connect to the MySQL database, and I export the instance for use in other parts of the application.

```
const { Sequelize } = require('sequelize');

const sequelize = new Sequelize('chatapp', 'root', 'password', {
  host: 'localhost',
  dialect: 'mysql'
});

(async () => {
  try {
    await sequelize.authenticate();
    console.log('Connection to the database has been established successfully.');
  } catch (error) {
    console.error('Unable to connect to the database:', error);
  }
})();

module.exports = sequelize;

```


### Models:
I create Sequelize models for User, Chatroom, and Message in their respective files within the models directory. These models define the structure of our tables and map them to JavaScript objects. Here is part of the code of User, full code will be available on github.

```
const { DataTypes } = require('sequelize');
const sequelize = require('../db');

const User = sequelize.define('User', {
  username: {
    type: DataTypes.STRING,
    allowNull: false,
    unique: true
  },
  email: {
    type: DataTypes.STRING,
    allowNull: false,
    unique: true
  },
  password: {
    type: DataTypes.STRING,
    allowNull: false
  }
}, {
  timestamps: false,
  tableName: 'users'
  
});

module.exports = {
  User
};

```

### Chat room management:
The chatroom.js file in the manager directory contains functions for creating, fetching, and deleting chat rooms. These functions interact with the Chatroom model to perform the necessary database operations. Here is part code, full code will be available on github.

```
const createChatroom = async (req, res) => {
  const { name, userId } = req.body;

  try {
    const chatroom = await Chatroom.create({ name, created_by: userId });
    //await ChatroomMember.create({ chatroom_id: chatroom.id, user_id: userId, joined_at: new Date() });

    res.status(201).json({ message: 'Chatroom created successfully', chatroom });
  } catch (error) {
    console.log('Create chatroom error:', error);
    res.status(500).json({ message: 'Server error', error });
  }
};

const getChatrooms = async (req, res) => {
  try {
    const chatrooms = await Chatroom.findAll();
    res.status(200).json({ chatrooms });
  } catch (error) {
    console.log('Get chatrooms error:', error);
    res.status(500).json({ message: 'Server error', error });
  }
};
```

### Message management:
The chatroom.js file also contains functions for fetching and creating messages within chat rooms. These functions interact with the Message model to perform the necessary database operations.

```
const getMessages = async (req, res) => {
  const chatroomId = req.params.chatroomId;

  try {
    const messages = await Message.findAll({ where: { chatroom_id: chatroomId } });
    res.status(200).json({ messages });
  } catch (error) {
    console.log('Get messages error:', error);
    res.status(500).json({ message: 'Server error', error });
  }
};


const createMessage = async (req, res) => {
  const { message_info, sender_id, chatroom_id } = req.body;

  try {
    const message = await Message.create({ message_info, sender_id, chatroom_id, created_at: new Date() });
    res.status(201).json({ message: 'Message sent successfully', message });
  } catch (error) {
    console.log('Create message error:', error);
    res.status(500).json({ message: 'Server error', error });
  }
};
```

### Authentication:
The auth.js file in the manager directory contains functions for user registration and login. We use the bcryptjs library to hash user passwords before storing them in the database, and we use the jsonwebtoken library to generate JSON Web Tokens for user authentication.

```
const register = async (req, res) => {
  const { username, email, password } = req.body;
  console.log('Register request:', req.body);

  try {
    const existingUser = await User.findOne({ where: { email } });
    if (existingUser) {
      return res.status(400).json({ message: 'User with this email already exists.' });
    }

    const hashedPassword = await bcrypt.hash(password, 12); 
    const newUser = await User.create({ username, email, password: hashedPassword }); 

    res.status(201).json({ message: 'User created successfully', user: newUser });
  } catch (error) {
    console.log('Register error:', error);
    res.status(500).json({ message: 'Server error', error });
  }
};

```

## Frontend Structure

I assume everyone knows HTML, CSS and JS, here I will just post the UI for the chat app in each web page. If you like to look at the frontend code, feel free to go to my github[https://github.com/Henryshi101/online_chat.git]

### login.html:

This file contains two forms, one for user registration and another for user login. The registration form collects the user's username, email, and password, and sends a POST request to the `/api/register` endpoint to register the user. The login form collects the user's email and password and sends a POST request to the `/api/login` endpoint to log in the user. Upon successful login, the user's ID and username are saved to sessionStorage and the user is redirected to the home.html page.


![login page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7b5xk0s5lnrkw0ly68gb.png)

### home.html:

This file displays a welcome message and a form for creating new chat rooms. When the form is submitted, a POST request is sent to the `/api/chatrooms` endpoint with the chat room's name and the user's ID. The list of chat rooms is fetched from the `/api/getChatrooms` endpoint and displayed on the page. Each chat room has a delete button that sends a DELETE request to the `/api/chatrooms/:id` endpoint to remove the chat room.

When a user clicks on a chat room name, they are redirected to the chat.html page, passing the chat room's ID and name in the URL.

![home](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9zqb90yub5nqxm4mvzr5.png)

### chat.html:

This file displays the chat room's name and a list of messages in the chat room. Messages are fetched from the `/api/chatrooms/:id/getMessages` endpoint and displayed on the page. The page also contains an input field for typing messages and a "Send" button to send the message. When the "Send" button is clicked, the message is sent to the `/api/chatrooms/:id/createMessage` endpoint as a POST request, along with the user's ID and the chat room's ID. The page updates the list of messages every 5 seconds to show new messages.

![Chat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nvt5vleyxhj1cj8d57wl.png)


## Conclusion

In this blog post, I have created a simple chat application using Node.js, Express, and MySQL. Due to the time concern, I just have those limited features. In the future, I may add up more features like add friends, create profile, private chat...
And also if you want to implement it in public network. You may need to host your website on a cloud server like AWS or Create a public link with Ngrok.