Simple Serverless Leaderboard API. It uses
AWS API Gateway
andAWS Lambda
to serve this Web API with Serverless model.Redis
to control the concurrent updates on the same ranking document.S3
to store it as permanently.
Since you are using Redis
, strictly speaking, this is not Serverless. This dependency will be removed in the future by implementing the web-based state management for ActorSystem
's concurrency control.
Request GET
to /{serviceId}/{period}?limit=<number>
with a header X-User
for userId
, then it returns by this form.
interface IRankRecord {
rank: number;
user: string;
score: string;
}
interface IRankView {
me: IRankRecord;
top: IRankRecord[];
around: IRankRecord[];
}
around
means somerecord
s near my rank which contains my rank, too.score
should bestring
because its value is bigger thanNumber.MAX_SAFE_INTEGER
.me
andaround
field can beundefined
when there is no my record.
$ curl "https://API-DOMAIN/STAGE/service_id/period" -H "X-User: test"
{
"top": [
{
"rank": 321,
"user": "test",
"score": "123456789123456789"
},
...
],
"around": [
...,
{
"rank": 321,
"user": "test",
"score": "123456789123456789"
},
...
],
"my": {
"rank": 321,
"user": "test",
"score": "123456789123456789"
},
}
Request GET
to /{serviceId}/{period}/me
with a header X-User
for userId
.
$ curl "https://API-DOMAIN/STAGE/service_id/period/me" -H "X-User: test"
{
"rank": 321,
"user": "test",
"score": "123456789123456789"
}
Request GET
to /{serviceId}/{period}/top?offset=<number>&limit=<number>
.
$ curl "https://API-DOMAIN/STAGE/service_id/period/top?offset=0&limit=10"
[{
"rank": 1,
"user": "test",
"score": "123456789123456789"
}, ...]
Request GET
to /{serviceId}/{period}/around?limit=<number>
with a header X-User
for userId
.
$ curl "https://API-DOMAIN/STAGE/service_id/period/around?limit=10" -H "X-User: test"
[..., {
"rank": 321,
"user": "test",
"score": "123456789123456789"
}, ...]
If you want to see more rankings from the current result, please request GET
to /{serviceId}/{period}/{direction}?cursor=<user>&limit=<number>
where direction
is one of up
and down
.
For example, if we want to see more 10 higher rankings from the test
user, it should request to /{serviceId}/{period}/up?cursor=test&limit=10
. This is because this user
field should be unique.
$ curl "https://API-DOMAIN/STAGE/service_id/period/up?limit=10"
[..., {
"rank": 320,
"user": "test2",
"score": "123456789123456799"
}]
Request PUT
to /{serviceId}/{period}
with a header X-User
for userId
, then it returns by the form that is same with GET my
API. The type of payload for score
is string
because it can be bigger than Number.MAX_SAFE_INTEGER
.
- This API doesn't update a record when an old score is higher than a new score.
- This API can be slow if there is so many concurrent
PUT
calls. It is because it is on the actor model to manage the consistency of ranks whiel updating concurrently. Please see details in benchmark.
$ curl -XPUT "https://API-DOMAIN/STAGE/service_id/period" -H "X-User: test" -d "123456789123456789"
{
"rank": 321,
"user": "test",
"score": "123456789123456789"
}
For admin purpose, it supports CLEAR
command via DELETE
request.
curl -XDELETE "https://API-DOMAIN/STAGE/service_id/period" -H "X-Auth: admin-secret"
But if process.env.AUTH_KEY
isn't set while deploying, X-Auth
can be omitted and it can lead very horrible problem, that is resetting all of ranks by anonymous.
- Install dependencies via
yarn
command from your shell. - After editing some codes, deploy this stack via
yarn deploy
command.
yarn
yarn deploy
It contains serverless-offline
plugin, you test it locally using yarn start
command.
yarn
yarn start
Also, you can debug this stack using yarn debug
command.
MIT