This is a standalone leaderboards service written with Express
and Mongoose
. This service is capable of doing the following things:
- Authenticate user with username & password (using
passportjs
) with customizable display name. - Support multiple leaderboards where each player can score indenpendently on.
- Single administration account which can delete user scores and see how many times an user submitted score in a time window.
- All scores are saved, allowing query the leaderboard in any time window (which also shows how many users submitted score in that time window).
- Persistent Websocket is used to broadcast score actions to all connected client.
Libray & Frameworks: Expresss, Mongoose, Jest, Passport, ws. The demo UI is created on CodeSandbox with React.js.
Create a .env
file with the content from .sample.env
and fill the informations:
MONGO_URI
: the URI to connect to your mongoDB database which will be used for serving.MONGO_URI_TEST
: the URI to connect to your mongoDB database which will be used for unit test.SESSION_SECRET
: the secret string used for cookie session.ADMIN_USERNAME
: credential for admin account.ADMIN_PASSWORD
: credential for admin account.ALLOW_ORIGIN
: the host domain of the client.
npm install
npm start
The application will be served at port 3000
for REST API & 4000
for Websocket server using nodemon
.
By default the origin is pointed to the demo UI website at https://38jw739r6q.codesandbox.io/. You can see the code for the UI at https://codesandbox.io/s/38jw739r6q. This website points to localhost
server, so you will need to get your server up and running, and if neccessary, change the HOST
value in config.js
of the UI code.
npm run test
The tests will be run by jest
with supertest
. You can also use npm run test-watch
to continously run the test.
The test is connected to the mongoDb database specified by MONGO_URI_TEST
environment variable. Before each test, this database will be dropped and all the data will be removed.
URL : /auth/register/
Method : POST
Auth required : NO
Data constraints
{
"username": "[username in plain text]",
"password": "[password in plain text]",
"displayName": "[OPTIONAL - String - default to username]"
}
Data example
{
"username": "test_user",
"password": "abcd1234",
"displayName": "Test User",
}
Response example
{
"displayName": "Test User",
"username": "test_user"
}
URL : /auth/login/
Method : POST
Auth required : NO
Data constraints
{
"username": "[username in plain text]",
"password": "[password in plain text]"
}
Data example
{
"username": "test_user",
"password": "abcd1234"
}
Response example
{
"displayName": "Test User",
"username": "test_user"
}
URL : /auth/profile/
Method : GET
Auth required : YES
Response example
{
"displayName": "Test User",
"username": "test_user"
}
URL : /auth/profile/
Method : PATCH
Auth required : YES
Data constraints
{
"displayName": "[displayName in plain text]"
}
Data example
{
"displayName": "New Name"
}
URL : /leaderboards/
Method : GET
Auth required : YES
Response example
[
"leaderboard_1",
"leaderboard_2"
]
URL : /leaderboards/:leaderboardName
Method : GET
Auth required : NO
Data constraints
{
"startTime": "[OPTIONAL - TimeStamp - specify time window]",
"endTime": "[OPTIONAL - TimeStamp - specify time window]",
"page": "[OPTIONAL - Number - the page to fetch, default to page 0]",
"perPage": "[OPTIONAL - Number - amount of users per page, default to 10]"
}
Response example
[
{
"username": "user1",
"displayName": "User 1",
"score": 10
},
{
"username": "user2",
"displayName": "User 2",
"score": 8
}
]
URL : /leaderboards/:leaderboardName
Method : POST
Auth required : YES
Data constraints
{
"score": "[Number - the score to record]"
}
URL : /leaderboards/:leaderboardName/users/:username
Method : DELETE
Auth required : ADMIN
URL : /leaderboards/:leaderboardName/userActions/:username
Method : GET
Auth required : ADMIN
Data constraints
{
"startTime": "[OPTIONAL - TimeStamp - specify time window]",
"endTime": "[OPTIONAL - TimeStamp - specify time window]"
}