{"id":15025252,"url":"https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit","last_synced_at":"2025-05-13T20:13:23.132Z","repository":{"id":39421779,"uuid":"56258294","full_name":"marcosbarbero/spring-cloud-zuul-ratelimit","owner":"marcosbarbero","description":"Rate limit auto-configure for Spring Cloud Netflix Zuul","archived":false,"fork":false,"pushed_at":"2025-05-08T04:27:02.000Z","size":1344,"stargazers_count":1137,"open_issues_count":2,"forks_count":387,"subscribers_count":86,"default_branch":"master","last_synced_at":"2025-05-08T13:35:01.260Z","etag":null,"topics":["bucket4j","consul","hacktoberfest","hacktoberfest2021","hashicorp-consul","load-shedding","loader","netflix-zuul","open-source","rate-limit","spring-cloud","spring-cloud-netflix","spring-cloud-netflix-zuul","throttle","throttling"],"latest_commit_sha":null,"homepage":"https://blog.marcosbarbero.com/spring-cloud-netflix-zuul-rate-limit/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marcosbarbero.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":"CONTRIBUTING.adoc","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"marcosbarbero"}},"created_at":"2016-04-14T17:49:19.000Z","updated_at":"2025-04-22T17:31:53.000Z","dependencies_parsed_at":"2023-02-15T14:01:37.821Z","dependency_job_id":"1fb119e3-a7e0-41fd-8dc1-93f357294bf5","html_url":"https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit","commit_stats":{"total_commits":501,"total_committers":20,"mean_commits":25.05,"dds":"0.39720558882235524","last_synced_commit":"36dc0a6815d020a280a805bd9ef68dbe37148018"},"previous_names":[],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosbarbero%2Fspring-cloud-zuul-ratelimit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosbarbero%2Fspring-cloud-zuul-ratelimit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosbarbero%2Fspring-cloud-zuul-ratelimit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosbarbero%2Fspring-cloud-zuul-ratelimit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcosbarbero","download_url":"https://codeload.github.com/marcosbarbero/spring-cloud-zuul-ratelimit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253838927,"owners_count":21972240,"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":["bucket4j","consul","hacktoberfest","hacktoberfest2021","hashicorp-consul","load-shedding","loader","netflix-zuul","open-source","rate-limit","spring-cloud","spring-cloud-netflix","spring-cloud-netflix-zuul","throttle","throttling"],"created_at":"2024-09-24T20:01:54.070Z","updated_at":"2025-05-13T20:13:23.095Z","avatar_url":"https://github.com/marcosbarbero.png","language":"Java","funding_links":["https://github.com/sponsors/marcosbarbero"],"categories":[],"sub_categories":[],"readme":"= Spring Cloud Zuul RateLimit image:https://app.travis-ci.com/marcosbarbero/spring-cloud-zuul-ratelimit.svg?branch=master[\"Build Status\", link=\"https://app.travis-ci.com/github/marcosbarbero/spring-cloud-zuul-ratelimit\"] image:https://coveralls.io/repos/github/marcosbarbero/spring-cloud-zuul-ratelimit/badge.svg?branch=master[\"Coverage Status\", link=\"https://coveralls.io/github/marcosbarbero/spring-cloud-zuul-ratelimit?branch=master\"] image:https://maven-badges.herokuapp.com/maven-central/com.marcosbarbero.cloud/spring-cloud-zuul-ratelimit/badge.svg[\"Maven Central\", link=\"https://maven-badges.herokuapp.com/maven-central/com.marcosbarbero.cloud/spring-cloud-zuul-ratelimit\"]\n:toc:\n\n:imagesdir: ./assets/images\n\n== Overview\nModule to enable rate limit per service in Netflix Zuul.\n\nThere are five built-in rate limit approaches:\n\n    * Authenticated User\n    ** Uses the authenticated username or 'anonymous'\n    * Request Origin\n    ** Uses the user origin request\n    * URL\n    ** Uses the request path of the downstream service\n    * URL Pattern\n    ** Uses the request Ant path pattern to the downstream service\n    * ROLE\n    ** Uses the authenticated user roles\n    * Request method\n    ** Uses the HTTP request method\n    * Request header\n    ** Uses the HTTP request header\n    * Global configuration per service:\n    ** This one does not validate the request Origin, Authenticated User or URI\n    ** To use this approach just don't set param 'type'\n\n[NOTE]\n====\nIt is possible to combine Authenticated User, Request Origin, URL, ROLE and Request Method just adding multiple values to the list \n====\n\n== Usage\n\n[NOTE]\n====\nLatest version: image:https://maven-badges.herokuapp.com/maven-central/com.marcosbarbero.cloud/spring-cloud-zuul-ratelimit/badge.svg[\"Maven Central\",link=\"https://maven-badges.herokuapp.com/maven-central/com.marcosbarbero.cloud/spring-cloud-zuul-ratelimit\"]\n====\n\n[NOTE]\n====\nIf you are using Spring Boot version `1.5.x` you *MUST* use Spring Cloud Zuul RateLimit version `1.7.x`.\nPlease take a look at the\nlink:https://mvnrepository.com/artifact/com.marcosbarbero.cloud/spring-cloud-zuul-ratelimit[Maven Central] and pick the\nlatest artifact in this version line.\n====\n\nAdd the dependency on pom.xml\n\n[source, xml]\n----\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.marcosbarbero.cloud\u003c/groupId\u003e\n    \u003cartifactId\u003espring-cloud-zuul-ratelimit\u003c/artifactId\u003e\n    \u003cversion\u003e${latest-version}\u003c/version\u003e\n\u003c/dependency\u003e\n----\n\nAdd the following dependency accordingly to the chosen data storage:\n\n\n* Redis\n\n[source, xml]\n----\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n    \u003cartifactId\u003espring-boot-starter-data-redis\u003c/artifactId\u003e\n\u003c/dependency\u003e\n----\n\n* Consul\n\n[source, xml]\n----\n\u003cdependency\u003e\n   \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n   \u003cartifactId\u003espring-cloud-starter-consul\u003c/artifactId\u003e\n\u003c/dependency\u003e\n----\n\n* Spring Data JPA\n\n[source, xml]\n----\n\u003cdependency\u003e\n   \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n   \u003cartifactId\u003espring-boot-starter-data-jpa\u003c/artifactId\u003e\n\u003c/dependency\u003e\n----\n\nThis implementation also requires a database table, bellow here you can find a sample script:\n\n[source, sql]\n----\nCREATE TABLE rate (\n  rate_key VARCHAR(255) NOT NULL,\n  remaining BIGINT,\n  remaining_quota BIGINT,\n  reset BIGINT,\n  expiration TIMESTAMP,\n  PRIMARY KEY(rate_key)\n);\n----\n\n* Bucket4j JCache\n\n[source, xml]\n----\n\u003cdependency\u003e\n     \u003cgroupId\u003ecom.github.vladimir-bukhtoyarov\u003c/groupId\u003e\n     \u003cartifactId\u003ebucket4j-core\u003c/artifactId\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n     \u003cgroupId\u003ecom.github.vladimir-bukhtoyarov\u003c/groupId\u003e\n     \u003cartifactId\u003ebucket4j-jcache\u003c/artifactId\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n     \u003cgroupId\u003ejavax.cache\u003c/groupId\u003e\n     \u003cartifactId\u003ecache-api\u003c/artifactId\u003e\n\u003c/dependency\u003e\n----\n\n* Bucket4j Hazelcast (depends on Bucket4j JCache)\n\n[source, xml]\n----\n\u003cdependency\u003e\n     \u003cgroupId\u003ecom.github.vladimir-bukhtoyarov\u003c/groupId\u003e\n     \u003cartifactId\u003ebucket4j-hazelcast\u003c/artifactId\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n     \u003cgroupId\u003ecom.hazelcast\u003c/groupId\u003e\n     \u003cartifactId\u003ehazelcast\u003c/artifactId\u003e\n\u003c/dependency\u003e\n----\n\n* Bucket4j Infinispan (depends on Bucket4j JCache)\n\n[source, xml]\n----\n\u003cdependency\u003e\n     \u003cgroupId\u003ecom.github.vladimir-bukhtoyarov\u003c/groupId\u003e\n     \u003cartifactId\u003ebucket4j-infinispan\u003c/artifactId\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n     \u003cgroupId\u003eorg.infinispan\u003c/groupId\u003e\n     \u003cartifactId\u003einfinispan-core\u003c/artifactId\u003e\n\u003c/dependency\u003e\n----\n\n* Bucket4j Ignite (depends on Bucket4j JCache)\n\n[source, xml]\n----\n\u003cdependency\u003e\n     \u003cgroupId\u003ecom.github.vladimir-bukhtoyarov\u003c/groupId\u003e\n     \u003cartifactId\u003ebucket4j-ignite\u003c/artifactId\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n     \u003cgroupId\u003eorg.apache.ignite\u003c/groupId\u003e\n     \u003cartifactId\u003eignite-core\u003c/artifactId\u003e\n\u003c/dependency\u003e\n----\n\nSample YAML configuration\n[source, yaml]\n----\nzuul:\n  ratelimit:\n    key-prefix: your-prefix\n    enabled: true\n    repository: REDIS\n    behind-proxy: true\n    add-response-headers: true\n    deny-request:\n      response-status-code: 404 #default value is 403 (FORBIDDEN)\n      origins:\n        - 200.187.10.25\n        - somedomain.com\n    default-policy-list: #optional - will apply unless specific policy exists\n      - limit: 10 #optional - request number limit per refresh interval window\n        quota: 1000 #optional - request time limit per refresh interval window (in seconds)\n        refresh-interval: 60 #default value (in seconds)\n        type: #optional\n          - user\n          - origin\n          - url\n          - http_method\n    policy-list:\n      myServiceId:\n        - limit: 10 #optional - request number limit per refresh interval window\n          quota: 1000 #optional - request time limit per refresh interval window (in seconds)\n          refresh-interval: 60 #default value (in seconds)\n          type: #optional\n            - user\n            - origin\n            - url\n        - type: #optional value for each type\n            - user=anonymous\n            - origin=somemachine.com\n            - url=/api #url prefix\n            - role=user\n            - http_method=get #case insensitive\n            - http_header=customHeader\n        - type:\n            - url_pattern=/api/*/payment\n----\n\nSample Properties configuration\n[source, properties]\n----\nzuul.ratelimit.enabled=true\nzuul.ratelimit.key-prefix=your-prefix\nzuul.ratelimit.repository=REDIS\nzuul.ratelimit.behind-proxy=true\nzuul.ratelimit.add-response-headers=true\n\nzuul.ratelimit.deny-request.response-status-code=404\nzuul.ratelimit.deny-request.origins[0]=200.187.10.25\nzuul.ratelimit.deny-request.origins[1]=somedomain.com\n\nzuul.ratelimit.default-policy-list[0].limit=10\nzuul.ratelimit.default-policy-list[0].quota=1000\nzuul.ratelimit.default-policy-list[0].refresh-interval=60\n\n# Adding multiple rate limit type\nzuul.ratelimit.default-policy-list[0].type[0]=user\nzuul.ratelimit.default-policy-list[0].type[1]=origin\nzuul.ratelimit.default-policy-list[0].type[2]=url\nzuul.ratelimit.default-policy-list[0].type[3]=http_method\n\n# Adding the first rate limit policy to \"myServiceId\"\nzuul.ratelimit.policy-list.myServiceId[0].limit=10\nzuul.ratelimit.policy-list.myServiceId[0].quota=1000\nzuul.ratelimit.policy-list.myServiceId[0].refresh-interval=60\nzuul.ratelimit.policy-list.myServiceId[0].type[0]=user\nzuul.ratelimit.policy-list.myServiceId[0].type[1]=origin\nzuul.ratelimit.policy-list.myServiceId[0].type[2]=url\n\n# Adding the second rate limit policy to \"myServiceId\"\nzuul.ratelimit.policy-list.myServiceId[1].type[0]=user=anonymous\nzuul.ratelimit.policy-list.myServiceId[1].type[1]=origin=somemachine.com\nzuul.ratelimit.policy-list.myServiceId[1].type[2]=url_pattern=/api/*/payment\nzuul.ratelimit.policy-list.myServiceId[1].type[3]=role=user\nzuul.ratelimit.policy-list.myServiceId[1].type[4]=http_method=get\nzuul.ratelimit.policy-list.myServiceId[1].type[5]=http_header=customHeader\n----\n\nBoth 'quota' and 'refresh-interval', can be expressed with https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-conversion-duration[Spring Boot's duration formats]:\n\n    * A regular long representation (using seconds as the default unit)\n    * The standard ISO-8601 format used by java.time.Duration (e.g. PT30M means 30 minutes)\n    * A more readable format where the value and the unit are coupled (e.g. 10s means 10 seconds)\n\n== Available implementations\n\nThere are eight implementations provided:\n\n[cols=2*, options=\"header\"]\n|===\n|Implementation        | Data Storage\n\n|ConsulRateLimiter     | https://www.consul.io/[Consul]\n\n|RedisRateLimiter      | https://redis.io/[Redis]\n\n|SpringDataRateLimiter | https://projects.spring.io/spring-data-jpa/[Spring Data]\n\n|Bucket4jJCacheRateLimiter\n\n.4+.^|https://github.com/vladimir-bukhtoyarov/bucket4j[Bucket4j]\n\n|Bucket4jHazelcastRateLimiter\n\n|Bucket4jIgniteRateLimiter\n\n|Bucket4jInfinispanRateLimiter\n\n|===\n\nBucket4j implementations require the relevant bean with `@Qualifier(\"RateLimit\")`:\n\n * `JCache` - javax.cache.Cache\n * `Hazelcast` - com.hazelcast.map.IMap\n * `Ignite` - org.apache.ignite.IgniteCache\n * `Infinispan` - org.infinispan.functional.ReadWriteMap\n\n== Common application properties\n\nProperty namespace: __zuul.ratelimit__\n\n|===\n|Property name| Values |Default Value\n\n|enabled             |true/false                   |false\n|behind-proxy        |true/false                   |false\n|response-headers    |NONE, STANDARD, VERBOSE      |VERBOSE\n|key-prefix          |String                       |${spring.application.name:rate-limit-application}\n|repository          |CONSUL, REDIS, JPA, BUCKET4J_JCACHE, BUCKET4J_HAZELCAST, BUCKET4J_INFINISPAN, BUCKET4J_IGNITE| -\n|deny-request        |link:./spring-cloud-zuul-ratelimit-core/src/main/java/com/marcosbarbero/cloud/autoconfigure/zuul/ratelimit/config/properties/RateLimitProperties.java#L296[DenyRequest]| -\n|default-policy-list |List of link:./spring-cloud-zuul-ratelimit-core/src/main/java/com/marcosbarbero/cloud/autoconfigure/zuul/ratelimit/config/properties/RateLimitProperties.java#L190[Policy]| -\n|policy-list         |Map of Lists of link:./spring-cloud-zuul-ratelimit-core/src/main/java/com/marcosbarbero/cloud/autoconfigure/zuul/ratelimit/config/properties/RateLimitProperties.java#L82[Policy]| -\n|postFilterOrder     |int                          |FilterConstants.SEND_RESPONSE_FILTER_ORDER - 10\n|preFilterOrder      |int                          |FilterConstants.FORM_BODY_WRAPPER_FILTER_ORDER\n\n|===\n\nDeny Request properties\n\n|===\n|Property name| Values |Default Value\n\n|origins              |list of origins to have the access denied | -\n|response-status-code |the http status code to be returned on a denied request | 403 (FORBIDDEN)\n\n|===\n\nPolicy properties:\n\n|===\n|Property name| Values |Default Value\n\n|limit           |number of requests      |  -\n|quota           |time of requests        |  -\n|refresh-interval|seconds                 | 60\n|type            | [ORIGIN, USER, URL, URL_PATTERN, ROLE, HTTP_METHOD, HTTP_HEADER] | []\n|breakOnMatch    |true/false              |false\n\n|===\n\n== Further Customization\n\nThis section details how to add custom implementations\n\n=== Key Generator\n\nIf the application needs to control the key strategy beyond the options offered by the type property then it can\nbe done just by creating a custom link:./spring-cloud-zuul-ratelimit-core/src/main/java/com/marcosbarbero/cloud/autoconfigure/zuul/ratelimit/config/RateLimitKeyGenerator.java[`RateLimitKeyGenerator`] beanfootnote:[By declaring a new `RateLimitKeyGenerator`, you replace the `DefaultRateLimitKeyGenerator`.]\nimplementation adding further qualifiers or something entirely different:\n\n[source, java]\n----\n  @Bean\n  public RateLimitKeyGenerator ratelimitKeyGenerator(RateLimitProperties properties, RateLimitUtils rateLimitUtils) {\n      return new DefaultRateLimitKeyGenerator(properties, rateLimitUtils) {\n          @Override\n          public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) {\n              return super.key(request, route, policy) + \":\" + request.getMethod();\n          }\n      };\n  }\n----\n\n=== Error Handling\nThis framework uses 3rd party applications to control the rate limit access and these libraries are out of control of this framework.\nIf one of the 3rd party applications fails, the framework will handle this failure in the\nlink:./spring-cloud-zuul-ratelimit-core/src/main/java/com/marcosbarbero/cloud/autoconfigure/zuul/ratelimit/config/repository/DefaultRateLimiterErrorHandler.java[`DefaultRateLimiterErrorHandler`] class\nwhich will log the error upon failure.\n\nIf there is a need to handle the errors differently, it can be achieved by defining a custom\nlink:./spring-cloud-zuul-ratelimit-core/src/main/java/com/marcosbarbero/cloud/autoconfigure/zuul/ratelimit/config/repository/RateLimiterErrorHandler.java[`RateLimiterErrorHandler`]\nbeanfootnote:[By declaring a new `RateLimitErrorHandler`, you replace the `DefaultRateLimitErrorHandler`.], e.g:\n\n[source, java]\n----\n  @Bean\n  public RateLimiterErrorHandler rateLimitErrorHandler() {\n    return new DefaultRateLimiterErrorHandler() {\n        @Override\n        public void handleSaveError(String key, Exception e) {\n            // custom code\n        }\n\n        @Override\n        public void handleFetchError(String key, Exception e) {\n            // custom code\n        }\n\n        @Override\n        public void handleError(String msg, Exception e) {\n            // custom code\n        }\n    }\n  }\n----\n\n=== Event Handling\nIf the application needs to be notified when a rate limit access was exceeded then it can be done by listening\nto link:./spring-cloud-zuul-ratelimit-core/src/main/java/com/marcosbarbero/cloud/autoconfigure/zuul/ratelimit/support/RateLimitExceededEvent.java[`RateLimitExceededEvent`] event:\n\n[source, java]\n----\n    @EventListener\n    public void observe(RateLimitExceededEvent event) {\n        // custom code\n    }\n----\n\n== Contributing\nSpring Cloud Zuul Rate Limit is released under the non-restrictive Apache 2.0 license, and follows a very\nstandard Github development process, using Github tracker for issues and merging pull requests into master.\nIf you want to contribute even something trivial please do not hesitate, but follow the guidelines below.\n\n=== Code of Conduct\nThis project adheres to the Contributor Covenant\nlink:CODE_OF_CONDUCT.md[code of conduct].\nBy participating, you are expected to uphold this code. Please report unacceptable behavior to marcos.hgb@gmail.com.\n\n=== Acknowledgement\n\nimage::jetbrains_logo.png[Jetbrains, 150, link=\"https://www.jetbrains.com/?from=spring-cloud-zuul-ratelimit\"]\n\n== Footnote\nAny doubt open an https://github.com/marcosbarbero/spring-cloud-starter-zuul-ratelimit/issues[issue].\nAny fix send me a https://github.com/marcosbarbero/spring-cloud-starter-zuul-ratelimit/pulls[Pull Request].\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcosbarbero%2Fspring-cloud-zuul-ratelimit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcosbarbero%2Fspring-cloud-zuul-ratelimit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcosbarbero%2Fspring-cloud-zuul-ratelimit/lists"}