Instabug chat API (BE Engineer challenge).
- Clone the repo
git clone https://github.com/civilcoder55/rails-api.git
- run containers
sudo docker-compose up -d
-
access api at http://localhost:3000/api/v1
-
access docs at http://localhost:4000/docs/
-
run specs
sudo docker run --rm -it insta-task-ror-image rspec
- click image to download insomnia api collection [can work with postman]
Method | URL | Description |
---|---|---|
GET |
/api/v1/applications |
Retrieve all applications. |
POST |
/api/v1/applications |
Create a new application. |
GET |
/api/v1/applications/:token |
Retrieve application by token. |
PUT |
/api/v1/applications/:token |
Update application by token. |
Method | URL | Description |
---|---|---|
GET |
/api/v1/applications/:token/chats |
Retrieve all application chats. |
POST |
/api/v1/applications/:token/chats |
Create a new application chat. |
GET |
/api/v1/applications/:token/chats/:number |
Retrieve application chat by number. |
Method | URL | Description |
---|---|---|
GET |
/api/v1/applications/:token/chats/:chat_number/messages |
Retrieve all chat messages. |
POST |
/api/v1/applications/:token/chats/:chat_number/messages |
Create a new chat message. |
GET |
/api/v1/applications/:token/chats/:chat_number/messages/:number |
Retrieve chat message by number. |
GET |
/api/v1/applications/:token/chats/:chat_number/messages?query=:search |
Search chat messages by query. |
-
for applications tokens :
- used SHA1 hash with random string + timestamp to ensure uniqueness .
-
for resources numbring :
- i choosed to keep tracking of numbring with cache store (Redis) instead of naive way of getting last resource number form database then increment it, so by this we save database hit
-
for hiding resouce ID :
- it can be done with many ways, maybe not selecting id when reading form database , or using serializers or even custom representers like what i did so i wrapped resource result with representer and i customed what fields should be returned
-
for identifying the application by its token and the chat by its number along with the application token
- i used nested resource to achieve this "/api/v1/applications/:token/chats/:number"
-
for partially search messages bodies with elasticsearch
- i used simple elasticsearch text mapping to make use of inverted index that supports very fast full-text searches.
-
to be running on multiple servers and race conditions
- for multiple server and centralized database and cache server scenario, we will have race condition when fetching and updating the next resource number for this we need some mutex locking, so redis provide us with atomic counter incr and also we don't need to locking as it's one atomic command.
-
to avoid writing directly to MySQL
- i used queuing systme to push write operations to, and a sidekiq worker to consume and do writes, for queuing we can use any queuing system like rabbitmq,sqs,redis - i choosed redis
-
for updating counts in database
- i used simple sidekiq cron task to run every 15 minutes to updated mysql columns from redis cache
-
i didn't implement pagination but for this i will go for cursor pagination because it perform better than offset
-
database indexing
- i added index for application token
- composite index for (application foriegn key + number) for chats and messages
- Ruby (2.7.6)
- Rails (5.2)
- ElasticSearch (7.13.4)
- MySQL
- Redis
- read and analyze task doc
- create new rails app and setup initial configs
- create database models and migrations
- create applications/chats/messages rest endpoints
- integrate elasticsearch for message searching
- add redis for chats/message counts tracking
- queue database writes with sidekiq/redis
- add counts updater cron
- write specs
- dockerize application stack
- optimizing
- create readme file