{"id":24926368,"url":"https://github.com/yingyeothon/leaderboard-api","last_synced_at":"2025-06-22T02:34:30.235Z","repository":{"id":42331178,"uuid":"202101237","full_name":"yingyeothon/leaderboard-api","owner":"yingyeothon","description":"A simple leaderboard API on AWS Serverless","archived":false,"fork":false,"pushed_at":"2023-10-27T03:45:24.000Z","size":802,"stargazers_count":1,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-28T12:29:43.075Z","etag":null,"topics":["aws","leaderboard","serverless"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yingyeothon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-13T08:39:16.000Z","updated_at":"2023-07-17T04:56:18.000Z","dependencies_parsed_at":"2025-02-02T12:52:01.351Z","dependency_job_id":"73d448c8-70fc-4719-9495-5219f27aa2a1","html_url":"https://github.com/yingyeothon/leaderboard-api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/yingyeothon/leaderboard-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yingyeothon%2Fleaderboard-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yingyeothon%2Fleaderboard-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yingyeothon%2Fleaderboard-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yingyeothon%2Fleaderboard-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yingyeothon","download_url":"https://codeload.github.com/yingyeothon/leaderboard-api/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yingyeothon%2Fleaderboard-api/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261225497,"owners_count":23127152,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","leaderboard","serverless"],"created_at":"2025-02-02T12:51:58.774Z","updated_at":"2025-06-22T02:34:25.224Z","avatar_url":"https://github.com/yingyeothon.png","language":"TypeScript","readme":"# Leaderboard API\n\n[![LoC](https://tokei.rs/b1/github/yingyeothon/leaderboard-api)](https://github.com/yingyeothon/leaderboard-api)\n[![Build Status](https://travis-ci.org/yingyeothon/leaderboard-api.svg?branch=master)](https://travis-ci.org/yingyeothon/leaderboard-api)\n[![Coverage Status](https://coveralls.io/repos/github/yingyeothon/leaderboard-api/badge.svg?branch=master)](https://coveralls.io/github/yingyeothon/leaderboard-api?branch=master)\n\nSimple Serverless Leaderboard API. It uses\n\n- `AWS API Gateway` and `AWS Lambda` to serve this Web API with Serverless model.\n- `Redis` to control the concurrent updates on the same ranking document.\n- `S3` to store it as permanently.\n\nSince 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.\n\n## Documentation\n\n### GET\n\n#### Get all\n\nRequest `GET` to `/{serviceId}/{period}?limit=\u003cnumber\u003e` with a header `X-User` for `userId`, then it returns by this form.\n\n```typescript\ninterface IRankRecord {\n  rank: number;\n  user: string;\n  score: string;\n}\ninterface IRankView {\n  me: IRankRecord;\n  top: IRankRecord[];\n  around: IRankRecord[];\n}\n```\n\n- `around` means some `record`s near my rank which contains my rank, too.\n- `score` should be `string` because its value is bigger than `Number.MAX_SAFE_INTEGER`.\n- `me` and `around` field can be `undefined` when there is no my record.\n\n```bash\n$ curl \"https://API-DOMAIN/STAGE/service_id/period\" -H \"X-User: test\"\n{\n  \"top\": [\n    {\n      \"rank\": 321,\n      \"user\": \"test\",\n      \"score\": \"123456789123456789\"\n    },\n    ...\n  ],\n  \"around\": [\n    ...,\n    {\n      \"rank\": 321,\n      \"user\": \"test\",\n      \"score\": \"123456789123456789\"\n    },\n    ...\n  ],\n  \"my\": {\n    \"rank\": 321,\n    \"user\": \"test\",\n    \"score\": \"123456789123456789\"\n  },\n}\n```\n\n#### Get `me` only\n\nRequest `GET` to `/{serviceId}/{period}/me` with a header `X-User` for `userId`.\n\n```bash\n$ curl \"https://API-DOMAIN/STAGE/service_id/period/me\" -H \"X-User: test\"\n{\n  \"rank\": 321,\n  \"user\": \"test\",\n  \"score\": \"123456789123456789\"\n}\n```\n\n#### Get `top` with `offset` and `limit`\n\nRequest `GET` to `/{serviceId}/{period}/top?offset=\u003cnumber\u003e\u0026limit=\u003cnumber\u003e`.\n\n```bash\n$ curl \"https://API-DOMAIN/STAGE/service_id/period/top?offset=0\u0026limit=10\"\n[{\n  \"rank\": 1,\n  \"user\": \"test\",\n  \"score\": \"123456789123456789\"\n}, ...]\n```\n\n#### Get `around` with `limit`\n\nRequest `GET` to `/{serviceId}/{period}/around?limit=\u003cnumber\u003e` with a header `X-User` for `userId`.\n\n```bash\n$ curl \"https://API-DOMAIN/STAGE/service_id/period/around?limit=10\" -H \"X-User: test\"\n[..., {\n  \"rank\": 321,\n  \"user\": \"test\",\n  \"score\": \"123456789123456789\"\n}, ...]\n```\n\n#### Scrolling from the result\n\nIf you want to see more rankings from the current result, please request `GET` to `/{serviceId}/{period}/{direction}?cursor=\u003cuser\u003e\u0026limit=\u003cnumber\u003e` where `direction` is one of `up` and `down`.\n\nFor example, if we want to see more 10 higher rankings from the `test` user, it should request to `/{serviceId}/{period}/up?cursor=test\u0026limit=10`. This is because this `user` field should be unique.\n\n```bash\n$ curl \"https://API-DOMAIN/STAGE/service_id/period/up?limit=10\"\n[..., {\n  \"rank\": 320,\n  \"user\": \"test2\",\n  \"score\": \"123456789123456799\"\n}]\n```\n\n### PUT\n\nRequest `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`.\n\n- **This API doesn't update a record when an old score is higher than a new score.**\n- 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](benchmark/README.md).\n\n```bash\n$ curl -XPUT \"https://API-DOMAIN/STAGE/service_id/period\" -H \"X-User: test\" -d \"123456789123456789\"\n{\n  \"rank\": 321,\n  \"user\": \"test\",\n  \"score\": \"123456789123456789\"\n}\n```\n\n### CLEAR\n\nFor admin purpose, it supports `CLEAR` command via `DELETE` request.\n\n```bash\ncurl -XDELETE \"https://API-DOMAIN/STAGE/service_id/period\" -H \"X-Auth: admin-secret\"\n```\n\nBut 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.\n\n## Deployment\n\n1. Install dependencies via `yarn` command from your shell.\n2. After editing some codes, deploy this stack via `yarn deploy` command.\n\n```bash\nyarn\nyarn deploy\n```\n\n## Development\n\nIt contains `serverless-offline` plugin, you test it locally using `yarn start` command.\n\n```bash\nyarn\nyarn start\n```\n\nAlso, you can debug this stack using `yarn debug` command.\n\n## License\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyingyeothon%2Fleaderboard-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyingyeothon%2Fleaderboard-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyingyeothon%2Fleaderboard-api/lists"}