Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/gozeloglu/leaderboard-redis
Leaderboard API implemented with Node.js and Redis.
https://github.com/gozeloglu/leaderboard-redis
hash nodejs redis sorted-set
Last synced: 5 days ago
JSON representation
Leaderboard API implemented with Node.js and Redis.
- Host: GitHub
- URL: https://github.com/gozeloglu/leaderboard-redis
- Owner: gozeloglu
- License: mit
- Created: 2021-01-23T10:21:56.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2021-01-28T20:08:01.000Z (almost 4 years ago)
- Last Synced: 2024-04-14T03:38:38.850Z (7 months ago)
- Topics: hash, nodejs, redis, sorted-set
- Language: JavaScript
- Homepage:
- Size: 87.9 KB
- Stars: 3
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Leaderboard - Redis
This is a **Node.js** implementation of the leadboard backend by using **Redis**. Project has basic features of the leaderboard operations like adding new player, storing scores and player information.
# Redis
**Redis** is an open-source, in-memory data structure store, used as a database, cache, and message broker. Redis has some nice data structures strings, hashes, lists, sets, sorted sets. To get more information from [here](https://redis.io/).
# Challenge
The challenge is updating the ranks when one of the player's rank is changed on the game. For example, player A's rank is 100th and its new rank will be 50th. All players' rank should be updated between 50th and 100th. Changing one of the player's rank affects the other player's rank.Especially, updating thousands of millions of players' ranks will be costly for your application if we update one-by-one each of the players.
# Why I used Redis?
To solve that problem, I used [sorted sets](https://redis.io/topics/data-types-intro#sorted-sets) in Redis. Basically, it stores unique key and its value. It does not allow to store duplicate keys. It is a nice feature, because players have unique IDs and I specified unique IDs as a key in sorted set. Also, it updates the rank with new scores automatically.
To store player's personal information, I used [hashes](https://redis.io/topics/data-types-intro#hashes). It keeps key-value pairs. Unlike the sorted set, it can keep more than one key-value pairs.
### Sorted Set Example
| Rank | Key (User ID) | Value (Score)|
|----------|:-------------:|------:|
| 0 | e4cdb120-28fc-4285-a78d-eb48660b7730| 123 |
| 1 | e4cdb120-28fc-4285-a78d-eb48660b7731| 234 |
| 2 | e4cdb120-28fc-4285-a78d-eb48660b7732 | 456 |
| ..| ...| ...|This is a sample sorted set structure of my solution. The keys and values are random. The important thing is that sorted sets sort the data in ascending order. That's why the key which has the minimum score is the first key in set. Also, sorted sets are zero-based.
### Hash Example
| Key (User ID) | Name | Points | Country |
| :-------------:|------:| :---------:| :-------:|
| e4cdb120-28fc-4285-a78d-eb48660b7730| Ahmet | 123 | tr |
| e4cdb120-28fc-4285-a78d-eb48660b7731| John | 234 | us |
| e4cdb120-28fc-4285-a78d-eb48660b7732 | Maria | 456 | uk |
| ...| ...| ...| ...|Basically, each player's personal information is stored in hashes. We can reach the hashes by using user ID.
# Runs
To run this project, you need to install `node` and `npm`. You can check them by typing the following commands.
```bash
$ node --version
$ npm --version
```If you need to install them, you can visit the following links:
* https://nodejs.org/en/download/
* https://www.npmjs.com/get-npmMy `npm` version is 6.14.5 and `node` version is v12.18.2.
Firstly, you need to install packages. To install them, run the following comamnd.
```bash
$ npm install
````Before running the project, be sure that you saved the **PORT**, **HOST**, and **PASSWORD** on your environment.
**Environment Variables:**
* `REDIS_HOST`
* `REDIS_PORT`
* `REDIS_PASSWORD`To run the project, you can enter the following command.
```bash
$ npm start
```To run the test, you can enter the following command.
```bash
$ npm run test
```# Endpoints
There are 5 different endpoints in my project.
### GET - All Leaderboard
Fetches the all leaderboard table and returns list of JSON objects.
```
/leaderboard
Example: http://localhost:8000/leaderboard
```The response will be list of JSON object format as follow:
```
[
{
"rank": 1,
"points": "282",
"display_name": "Gökhan",
"country": "tr"
},
{
"rank": 2,
"points": "247",
"display_name": "Ahmet",
"country": "tr"
},
{
"rank": 3,
"points": "40",
"display_name": "Cenk",
"country": "tr"
},
{
"rank": 4,
"points": "0",
"display_name": "John",
"country": "us"
},
{
"rank": 5,
"points": "0",
"display_name": "David",
"country": "es"
},
{
"rank": 6,
"points": "0",
"display_name": "Karem",
"country": "fr"
}
]
```### GET - Leaderboard by Country
Fetches the all leaderboard table for given country code.
```
/leaderboard/
Example: http://localhost:8000/leaderboard/tr
```The response will be list of JSON objects that includes the player information from given country. If there is no such a country, it will return a error message.
```
[
{
"rank": 1,
"points": "282",
"display_name": "Gökhan",
"country": "tr"
},
{
"rank": 2,
"points": "247",
"display_name": "Ahmet",
"country": "tr"
},
{
"rank": 3,
"points": "40",
"display_name": "Cenk",
"country": "tr"
}
]
```### GET - User Profile
Fetches the user profile by using user id.
```
/user/profile/
Example: http://localhost:8000/user/profile/e4cdb120-28fc-4285-a78d-eb48660b7730
```The response will be JSON object that includes the user profile. If there is no such a player, it will return a string that tells there is no this player.
```
{
"user_id": "e4cdb120-28fc-4285-a78d-eb48660b7730",
"display_name": "David",
"points": "0",
"rank": 7,
"country": "gr"
}
```### POST - Submit Score
Submits the new score for given player. It increments the player's score with new score.
```
/score/submit
Example: http://localhost:8000/score/submit
Body:
{
"score_worth": 1,
"user_id": "e4cdb120-28fc-4285-a78d-eb48660b7730",
"timestamp": 1611433105
}
```
The body includes score worth, user id, and timestamp. Timestamp is compared with the current timestamp to check the time is in past or not. If the given timestamp in future, the score will not be updated and returns an error message. If the timestamp is in the now or past, the score will be updated. I am not storing the timestamp in Redis.**SUCCESSFUL SUBMIT**
```
Player's new score is: 2
Player's rank is: 4th
```**UNSUCCESSFUL SUBMIT**
```
{
msg: "Player could not find!"
}
```The response will be a string that includes a message with new rank and new score. If the user id does not exist in Redis, unsuccessful submit message will be returned.
### POST - User Create
Creates a new user and saves on the Redis.
```
/user/create
Example: http://localhost:8000/user/create
Body:
{
"user_id": "e4cdb120-28fc-4285-a78d-eb48660b7730",
"display_name": "David",
"points": 0,
"country": "gr"
}
```The body includes user id, user name, total points, and country. Rank is not added to the body because Redis determines the rank. That's why there is no need to add rank information on the body.
```
{
"user_id": "e4cdb120-28fc-4285-a78d-eb48660b7730",
"display_name": "David",
"points": 0,
"rank": 7,
"country": "gr"
}
```
The response will be the same JSON object. Rank is added to body object in request. The rank will be determined by alphabetical order if the scores is the same.### DELETE - Delete User
Deletes the user by user id from Redis DB.
```
/user/delete/
Example: http://localhost:8000/user/delete/e4cdb120-28fc-4285-a78d-eb48660b7730
```Returns a JSON object that includes the success or error messages by result of the delete operation.
#### Success message
```
{
"success_message": "e4cdb120-28fc-4285-a78d-eb48660b7730 is removed"
}
```#### Error message
```
{
"error_message": "User could not removed from sorted set."
}
```or
```
{
"error_message": "User could not removed from hash."
}
```