{"id":18489113,"url":"https://github.com/hachreak/limitless_service","last_synced_at":"2025-09-02T16:36:23.881Z","repository":{"id":139147318,"uuid":"89947116","full_name":"hachreak/limitless_service","owner":"hachreak","description":"Rate-limiters As A Service (RLAAS)","archived":false,"fork":false,"pushed_at":"2017-06-04T12:51:37.000Z","size":36,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-23T18:06:34.207Z","etag":null,"topics":["api","cluster","distributed-systems","erlang","erlang-libraries","erlang-library","microservice","rate-limiter","rate-limits","rest","rest-api","service","swagger","websocket","websockets"],"latest_commit_sha":null,"homepage":"https://github.com/hachreak/limitless_service","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hachreak.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":"2017-05-01T17:44:27.000Z","updated_at":"2023-05-11T00:32:36.000Z","dependencies_parsed_at":null,"dependency_job_id":"077e8f26-e5c4-4661-9f81-b498d395bb46","html_url":"https://github.com/hachreak/limitless_service","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hachreak%2Flimitless_service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hachreak%2Flimitless_service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hachreak%2Flimitless_service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hachreak%2Flimitless_service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hachreak","download_url":"https://codeload.github.com/hachreak/limitless_service/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247931027,"owners_count":21020153,"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":["api","cluster","distributed-systems","erlang","erlang-libraries","erlang-library","microservice","rate-limiter","rate-limits","rest","rest-api","service","swagger","websocket","websockets"],"created_at":"2024-11-06T12:55:19.139Z","updated_at":"2025-04-08T21:30:41.360Z","avatar_url":"https://github.com/hachreak.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"limitless_service\n=================\n\nRate-limiters As A Service (RLAAS):\nREST + Websocket API microservice interface for Limitless.\n\nThe application is using the in-memory distributed master-less document\ndatabase [minidb](https://github.com/hachreak/minidb) to be able to create\na cluster and scale horizontally.\n\nAPI\n---\n\nAPI                          | REST         | Websocket\n-----------------------------|--------------|-------------\nSetup limits for a `object`. | Implemented  | Implemented\nAsk if limit reached.        | Implemented  | Implemented\n\nYou can connect to the service through a REST or Websocket API.\n\nThe endpoints are defined by a unique swagger (OpenAPI) configuration.\nThe [swagger_routerl](https://github.com/hachreak/swagger_routerl) is used to\ninstantiate them.\n\nTo get the swagger file, run the instance and get\n`http://127.0.0.1:8080/1.0.0/docs/swagger.yaml` or\nopen the file `priv/docs/swagger.yaml`.\n\nYou can choose to connect to the service every time you need making a REST call\nor leave a connections pool open to the websocket endpoint `/websocket` of\none o more server in a cluster.\n\nBoth interface are stateless. It means that you easily scale the service.\n\n### Configure limits\n\nIn our example, we configure (see `limitless.config`) the object group\n`token`.\n\n```erlang\n    {limits, [\n      % group name: token.\n      {token, [\n        % This group incude two limit types:\n        [\n          % max 1000 req/day\n          {type, \u003c\u003c\"Token-Daily\"\u003e\u003e},\n          {frequency, 86400}, % 1 day = 3600 * 24h\n          {requests, 1000}\n        ],\n        [\n          % max 100 req/15min\n          {type, \u003c\u003c\"Token-15min\"\u003e\u003e},\n          {frequency, 900}, % 15 min = 60 * 15\n          {requests, 100}\n        ]\n      ]}\n    ]}\n```\n\nBut you can use the group name you want and also define multiple groups\n(e.g. a group for tokens and a group for users).\n\nSee `etc/limitless.config` for a complete configuration example.\n\n### Setup limits for a object\n\nIn your application, at the moment a new token is created, you'll associate\nto it the limits defined by the `token` group:\n\n**--\u003e REST example**\n\n    $ http PUT :8080/api/objects/token1/groups/token Content-type:application/json\n\nYou should receive a response:\n\n```http\nHTTP/1.1 204 No Content\ncontent-length: 0\ncontent-type: application/json\ndate: Mon, 15 May 2017 21:30:17 GMT\nserver: Cowboy\n```\n\n**--\u003e Websocket example**\n\nSend the message\n\n```\n{\"path\": \"/objects/token1/groups/token\", \"method\": \"put\"}\n```\n\nYou should receive a response:\n\n```json\n{\"context\": {}, \"result\": \"ok\"}\n```\n\n### Ask if the object reach one of defined limits\n\nEvery time you'll receive a request containing a token, you can ask if it\nhas reached any defined limits.\n\n**--\u003e REST example**\n\n    $ http PUT :8080/api/objects/token1/_isreached Content-type:application/json\n\nYou should receive a response:\n\n```http\nHTTP/1.1 200 OK\ncontent-length: 190\ncontent-type: application/json\ndate: Mon, 15 May 2017 21:31:32 GMT\nserver: Cowboy\n\n{\n    \"info\": [\n        {\n            \"extra\": [\n                {\n                    \"expiry\": 811,\n                    \"type\": \"Token-15min\",\n                    \"max\": 100,\n                    \"remaining\": 90\n                },\n                {\n                    \"expiry\": 86311,\n                    \"type\": \"Token-Daily\",\n                    \"max\": 1000,\n                    \"remaining\": 970\n                }\n            ],\n            \"is_reached\": false\n        }\n    ],\n    \"is_reached\": false\n}\n```\n\n**--\u003e Websocket example**\n\nSend the message\n\n```json\n{\"path\": \"/objects/token1/_isreached\", \"method\": \"put\"}\n```\n\nYou'll receive something like:\n\n```json\n{\n  \"context\": {\n    \"info\": [{\n      \"extra\": [{\n        \"expiry\": 811,\n        \"type\": \"Token-15min\",\n        \"max\": 100,\n        \"remaining\": 90\n      }, {\n        \"expiry\": 86311,\n        \"type\": \"Token-Daily\",\n        \"max\": 1000,\n        \"remaining\": 970\n      }],\n      \"is_reached\": false\n    }],\n    \"is_reached\": false\n  },\n  \"result\": \"ok\"\n}\n```\n\nThe most important information is last `is_reached`: it's saying to you if\nthere is a limit reached for the `token1`.\nIf it's true, you'll block the request.\n\nIn this case is `false` and it means that the request can be processed.\n\nInside `\"extra\"` you can find some interesting information useful to build\ngeneral informations about the state of all limits.\n\nIn case you are implementing a REST API, they are usefull to build the\n`X-RateLimiter-Token-XXX` HTTP headers.\n\nE.g.\n\n```\nX-RateLimit-Token-Daily-Limit: 1000\nX-RateLimit-Token-Daily-Remaining: 970\nX-RateLimit-Token-Daily-Reset: 86311\nX-RateLimit-Token-15min-Limit: 100\nX-RateLimit-Token-15min-Remaining: 90\nX-RateLimit-Token-15min-Reset: 811\n```\n\n\nMake a servers cluster\n----------------------\n\nOpen the first console and run:\n\n    $ make node1\n\nIn another console run:\n\n    $ make node2\n\nNode 2 will automatically connect after 5 second to the node 1 in cluster.\n\nNow you can open a websocket connect to `ws://127.0.0.1:8080/websocket` or to\n`ws://127.0.0.1:8081/websocket`.\nOr make a REST call to one of them.\n\nThe node you are choosing is not relevant. Any node can be used.\n\nAt client side can be useful create a connection pool and have connections\nwith all of them.\n\nRun with docker\n---------------\n\nThere is an example of instance running on docker:\n\n    $ docker-compose build\n    $ docker-compose up\n\nNow you will have a node available on `ws://127.0.0.1:8080/websocket`\nor REST API at `http://127.0.0.1:8080/api`.\n\nRun a release\n-------------\n\n    $ rebar3 release\n    $ rebar3 run\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhachreak%2Flimitless_service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhachreak%2Flimitless_service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhachreak%2Flimitless_service/lists"}