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
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
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
.
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.
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{ name: string }
{ "success": boolean, "token": string }
-
Get All Applications Endpoint :
GET /applications/
used for getting all created applications[ { "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{ "name": string, "token": string, "chats_count": number }
-
Edit Application Endpoint :
PATCH /applications/:token
used to update application name{ name: string }
{ "success": boolean, "message": "successfully updated" }
-
Create Chat Endpoint :
POST /applications/:token/chat
used for creating a chat inside an application{ name: string }
{ "success": boolean, "chat_number": number }
-
Get All Chats Endpoint :
GET /applications/:token/chats
used for getting all chats of an applications[ { "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[ { "name": string, "messages_count": number, "chat_number": number, } ]
-
Edit Chat Endpoint :
PATCH /applications/:token/chats/:chat_number
used to update chat name{ name: string }
{ "success": boolean, "message": "successfully updated" }
-
Create Message Endpoint :
POST /applications/:token/chats/:chat_number/message
used to create a message inside a chat{ "sender": string, "content": string }
{ "success": boolean, "message_number": number }
-
Get All Messages Endpoint :
GET /applications/:token/chats/:chat_number/messages
used to get all messages inside a chat[ { "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{ "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{ "sender": string, "content": string }
{ "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[ { "sender": string, "content": string, "message_number": number } ]
Tests are built using rspec, and can be run using rspec
command
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).
- name : name of application
- 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
- name : name of chat
- 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
- sender : sender of the message