Chat App

A backend application for handling a chat application
App is responsible for crating new sub-application each will have a number of chats and each chat can have a number of messages
This is a Ruby on Rails application. MySQL is used as a DB, Redis for caching, Rabbit MQ as broker and Elasticsearch for searching messages

Description

The application allows user creating new applications where each application will have a token (generated by the system) and a name(provided by the user).
The token is the identifier that devices use to send chats to that application. Each application can have many chats. a chat have a number.
Numbering of chats in each application starts from 1 and no two chats in the same application will have the same number.
The number of the chat is returned in the chat creation request. A chat contains messages and messages have numbers that start from 1 for each chat. The number of the message is also returned in the message creation request.
The client identifies the application by its token and the chat by its number along with the application token.
Transactions with isolation level serializable are being used for chats and messages creation in order to avoid race conditions.
There is an endpoint for searching through messages of a specific chat using Elasticsearch

Installation

Clone the Github repository and use docker to start the application

$ git clone https://github.com/hazem-elsaayed/chat-app.git
$ cd chat-app
$ docker-compose up

Wait for some time unitll docker fetches the images, build and run them then make sure this message appears in the terminal window Listening on http://0.0.0.0:3000 and default rails page is running on http://localhost:3000.

Notes

To avoid race conditions for creating chats and messages, rabbit mq is used so the requests will be published to a queue and will be consumed (one by one) by one consumer which will then create them in DB
For updating endpoints, DB locks are used to permit only one request to update the row so if one transaction is updating the row the second transaction will be forced to wait until the first is completed and the lock is released before it can make updates.

Usage

This app has 13 endpoints user can use to create applications, chats & messages, you can view and try them using swagger endpoint http://127.0.0.1:3000/api-docs/index.html or check the details below :-

  • Create Application Endpoint : POST /application/ used for creating an application

    Request Body Params

    { name: string } 
    

    Response

      {
        "success": boolean,
        "token": string
      }
    
  • Get All Applications Endpoint : GET /applications/ used for getting all created applications

    Response

      [
          {
              "name": string,
              "token": string,
              "chats_count": number,
          }
      ]
    
  • Get Single Applications Endpoint : GET /applications/:token used to get a single application data given it's token

    Response

      {
        "name": string,
        "token": string,
        "chats_count": number
      }
    
  • Edit Application Endpoint : PATCH /applications/:token used to update application name

    Request Body Params

    { name: string } 
    

    Response

      {
        "success": boolean,
        "message": "successfully updated"
      }
    
  • Create Chat Endpoint : POST /applications/:token/chat used for creating a chat inside an application

    Request Body Params

    { name: string } 
    

    Response

      {
        "success": boolean,
        "chat_number": number
      }
    
  • Get All Chats Endpoint : GET /applications/:token/chats used for getting all chats of an applications

    Response

      [
        {
          "name": string,
          "messages_count": number,
          "chat_number": number,
        }
      ]
    
  • Get Single Chat Endpoint : GET /applications/:token/chats/:chat_number used to get a single chat data given it's number and application token

    Response

      [
        {
          "name": string,
          "messages_count": number,
          "chat_number": number,
        }
      ]
    
  • Edit Chat Endpoint : PATCH /applications/:token/chats/:chat_number used to update chat name

    Request Body Params

    { name: string } 
    

    Response

      {
        "success": boolean,
        "message": "successfully updated"
      }
    
  • Create Message Endpoint : POST /applications/:token/chats/:chat_number/message used to create a message inside a chat

    Request Body Params

      {
        "sender": string,
        "content": string
      }
    

    Response

      {
        "success": boolean,
        "message_number": number
      }
    
  • Get All Messages Endpoint : GET /applications/:token/chats/:chat_number/messages used to get all messages inside a chat

    Response

      [
        {
          "sender": string,
          "content": string,
          "message_number": number,
        }
      ]
    
  • Get a Message Endpoint : GET /applications/:token/chats/:chat_number/messages/:message_number used to specific message inside a chat

    Response

      {
        "sender": string,
        "content": string,
        "message_number": number,
      }
    
  • Edit a Message Endpoint : PATCH /applications/:token/chats/:chat_number/messages/:message_number used to update sender or message of a specific chat

    Request Body Params

      {
        "sender": string,
        "content": string
      }
    

    Response

      {
        "success": true,
        "message": "successfully updated"
      }
    
  • Search a chat Endpoint : PATCH /applications/:token/chats/:chat_number/messages/search?query='string' search for a string inside a chat's messages

    Response

      [
        {
          "sender": string,
          "content": string,
          "message_number": number
        }
      ]
    

Testing

Tests are built using rspec, and can be run using rspec command

Models

3 models are used to store data

  • Applications model : in which applications are stored and it has the following properties:
    • name : name of application
    • token : unique string identifying each application. (this column has an index)
    • chats_count : number of chats inside the application. (gets updated by a cron job every 45 mins)
    • createdAt, updatedAt : (timestamp).
  • Chats model : in which Chats data are stored and it has the following property:
    • name : name of chat
    • chat_number : unique number in each application for each chat. (this column has an index)
    • messages_count : number of messages inside the chat. (gets updated by a cron job every 45 mins)
    • application_id : foreign key with refrence to the application id
  • Messages model : in which Messages data are stored and it has the following property:
    • sender : sender of the message
    • content : contents of the message
    • message_number : unique number in each chat for each message. (this column has an index)
    • chat_id : foreign key with refrence to the chat id