P.S: I never used rails nor ruby, docker, elastic search before now, the project runs good if you're using running local 'elasticseach' and 'rabbitmq' CLI commands, but with docker i faced some issues connecting to mysql database!
P.S: i'm using the latest version of docker and docker compose, the command runs docker compose up --build --force-recreate
, build
flag is used to run dockerfile when building images, force-recreate
flag is used to recreate the image if you have it already existing on your device.
We will only write docker-compose up to run the whole stack.
It’s required to build a chat system. The system should allow creating new applications where each application will have a token(generated by the system) and a name(provided by the client). The token is the identifier that devices use to send chats to that application. Each application can have many chats. a chat should have a number. Numbering of chats in each application starts from 1 and no 2 chats in the same application may have the same number. The number of the chat should be 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 should also be returned in the message creation request. The client should never see the ID of any of the entities. The client identifies the application by its token and the chat by its number along with the application token.
We need you to create a RESTful API to simulate this behavior: * create an application with unique generated token by code and name by user. * create a chat in a certain application. * create a message in a certain chat. * get chats in an application. * get messages in a chat. * search for a message parial or full body with elasticsearch.
* Elasticsearch with partial filtering for messaging allowing partial and full text search.
* Try to minimize the queries and avoid writing directly to MySQL while serving the
requests
* You should add a Readme containing instructions to run your code.
* You should use Ruby on Rails(V5)
* Use MySQL as your main datastore. You’re allowed to use any other component you
need along with MySQL. You may want to check out REDIS.
* Write APIs in golang
* Write specs for your code.
Installing ruby on rails V5 using RVM, and creating an API boiler plate with this tutorial https://www.youtube.com/watch?v=QojnRc7SS9o&t=125s
Create three database models:
apps
chats
messages
$ rails g model apps token:string name:text chats_count:integer
$ rails g model chats app_token:string chat_id:integer messages_count:integer
$ rails g model messages chat_id:integer body:text app_token:string
=========================================================================================
A design choice here was to add app_token
in each chat
record instead of making a multi-variate attribute in apps
table, so that we can check if chat_id
exists for app_token
without the need to iterate through all chat ids for a specific application!
-
The system should allow creating new applications where each application will have a token(generated by the system) and a name(provided by the client). The token is the identifier that devices use to send chats to that application.
-- created an end-point for creating new applications, accepts 'name' as a body parameter from user, then generate a unique random hex string to be a primary key for each application.
-
Each application can have many chats. a chat should have a number. Numbering of chats in each application starts from 1 and no 2 chats in the same application may have the same number
-- created and end-point for registering a new chat using 'app_token' as a parameter, then get 'chats_count' attribute for that application and assign the
chat_id
attribute to be 'chats_count+1', then no chats in the same applications will have the same id -
A chat contains messages and messages have numbers that start from 1 for each chat. The number of the message should also be returned in the message creation request
-- created an end-point for registering a new message to a specific chat taking
app_token
,chat_id
andbody
of the message as a parameter, returning number of messages of thechat
record. -
Add an endpoint for searching through messages of a specific chat. It should be able to partially match messages’ bodies. You must use ElasticSearch for this.
--configured elasticsearch with the
messages
model to update it-self as themessages
table be modified/added to/ deleted, it uses Ngrams (trigrams my case) to compare texts, i used it with message body as that's the text we want to search, it breaks each word in N parts ( three my case ) so it could compare words together. -
The applications table should contain a column called chats_count that contains the number of chats for this application. Similarly, the chats table should contain a column called messages_count that contains the number of messages in this chat.
-- configured above when creating database models.
-
Try to minimize the queries and avoid writing directly to MySQL while serving the requests(especially for the chats and messages creation endpoints). You can use a queuing system to achieve that.
-- configured rabbitmq service for that, a rabbitmq publisher is called when adding a new application to our system.
-
Your app should be containerized. We should only write
docker-compose up
to run the whole stack.-- configured docker-compose.yml file and Dockerfile to containarize the whole stack (rabbitmq, rails, elasticsearch, mysql), although i couldn't connect to mysql correctly using docker.
========================================================================================
Elasticsearch container.
Rabbitmq container.
Rails container.
mysql container.
getting ready out of the box images for rabbitmq, elasticsearch, mysql, looking online to see how others could containarize rails app with multiple images made it easier.
Getting rails image to connect with mysql image: - when running $(docker compose up --build --force-recreate) in terminal all images run correctly, but rails app can't connect to mysql database.
- tried multiple solutions available online like `stackoverflow` and others..., but no solution worked although i could connect to mysql with terminal meaning the image is running correct, and couldn't find issue with my configurations, i'm sure that there's a solution somewhere but i couldn't get it in time.
I exposed rails api on port 3000 and elasticsearch on port 9200
- Create New application
POST request.
URL: http://localhost:3000/api/v1/applications
BODY PARAMS: name
- update application name
PUT request.
URL: http://localhost:3001/applications/<app_token>
BODY PARAMS: app_token
, name
- get application
GET request.
URL: http://localhost:3000/api/v1/applications/<app_token>
BODY PARAMS: app_token
- create a new chat
POST request.
URL: http://localhost:3000/api/v1/chats
BODY PARAMS: app_token
#that you want to assign the chat to
- get all application chats
GET request.
URL: http://localhost:3000/api/v1/chats/<app_token>
BODY PARAMS: app_token
- create a new message
POST request.
URL: http://localhost:3000/api/v1/messages
BODY PARAMS: app_token
, chat_id
, body
- get all message in a chat
GET request.
URL: http://localhost:3000/api/v1/messages
BODY PARAMS: app_token
, chat_id
.
- search a message (partially or fully)
curl -X POST
http://localhost:9200/messages/_search
-H 'cache-control: no-cache'
-H 'content-type: application/json'
-d '{
"query": {
"match": {
"body": 'text'
}
}
}'
TODO
* fix rails image connection to sql image.
* write testcases to address all scenarios.