diff --git a/spring-cloud/spring-cloud-zuul-throttling/pom.xml b/spring-cloud/spring-cloud-zuul-throttling/pom.xml
index 180cc96f00..b34ade662a 100644
--- a/spring-cloud/spring-cloud-zuul-throttling/pom.xml
+++ b/spring-cloud/spring-cloud-zuul-throttling/pom.xml
@@ -37,7 +37,7 @@
com.marcosbarbero.cloud
spring-cloud-zuul-ratelimit
- LATEST
+ 2.2.0.RELEASE
org.springframework.boot
diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java
index 18a779f976..cc13b7a046 100644
--- a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java
+++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java
@@ -1,12 +1,53 @@
package com.baeldung.spring.cloud.zuulratelimitdemo;
+import javax.servlet.http.HttpServletRequest;
+
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.zuul.filters.Route;
+import org.springframework.context.annotation.Bean;
+
+import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimitKeyGenerator;
+import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimitUtils;
+import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties.RateLimitProperties;
+import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.repository.RateLimiterErrorHandler;
+import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.repository.DefaultRateLimiterErrorHandler;
+import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.DefaultRateLimitKeyGenerator;
@SpringBootApplication
public class ZuulRatelimitDemoApplication {
- public static void main(String[] args) {
- SpringApplication.run(ZuulRatelimitDemoApplication.class, args);
- }
+ public static void main(String[] args) {
+ SpringApplication.run(ZuulRatelimitDemoApplication.class, args);
+ }
+
+ @Bean
+ public RateLimitKeyGenerator ratelimitKeyGenerator(RateLimitProperties properties, RateLimitUtils rateLimitUtils) {
+ return new DefaultRateLimitKeyGenerator(properties, rateLimitUtils) {
+ @Override
+ public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) {
+ return super.key(request, route, policy) + ":" + request.getMethod();
+ }
+ };
+ }
+
+ @Bean
+ public RateLimiterErrorHandler rateLimitErrorHandler() {
+ return new DefaultRateLimiterErrorHandler() {
+ @Override
+ public void handleSaveError(String key, Exception e) {
+ // custom code
+ }
+
+ @Override
+ public void handleFetchError(String key, Exception e) {
+ // custom code
+ }
+
+ @Override
+ public void handleError(String msg, Exception e) {
+ // custom code
+ }
+ };
+ }
}
diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java
index 4a27324b4d..f0facc621a 100644
--- a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java
+++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java
@@ -11,16 +11,16 @@ import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/greeting")
public class GreetingController {
- public static final String SIMPLE_RESPONSE = "Hi!";
- public static final String ADVANCED_RESPONSE = "Hello, how you doing?";
+ public static final String SIMPLE_RESPONSE = "Hi!";
+ public static final String ADVANCED_RESPONSE = "Hello, how you doing?";
- @GetMapping("/simple")
- public ResponseEntity serviceA() {
- return ResponseEntity.ok(SIMPLE_RESPONSE);
- }
+ @GetMapping("/simple")
+ public ResponseEntity getSimple() {
+ return ResponseEntity.ok(SIMPLE_RESPONSE);
+ }
- @GetMapping("/advanced")
- public ResponseEntity serviceB() {
- return ResponseEntity.ok(ADVANCED_RESPONSE);
- }
+ @GetMapping("/advanced")
+ public ResponseEntity getAdvanced() {
+ return ResponseEntity.ok(ADVANCED_RESPONSE);
+ }
}
diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml b/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml
index 884ee9446e..86a29ca06d 100644
--- a/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml
+++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml
@@ -11,13 +11,13 @@ zuul:
repository: JPA
policy-list:
serviceSimple:
- - limit: 5
- refresh-interval: 60
- type:
- - origin
+ - limit: 5
+ refresh-interval: 60
+ type:
+ - origin
serviceAdvanced:
- - limit: 1
- refresh-interval: 2
- type:
- - origin
- strip-prefix: true
+ - limit: 1
+ refresh-interval: 2
+ type:
+ - origin
+ strip-prefix: true
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java
index 360d005c43..fe81838d5d 100644
--- a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java
+++ b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java
@@ -28,73 +28,86 @@ import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class GreetingControllerTest {
- private static final String SIMPLE_GREETING = "/greeting/simple";
- private static final String ADVANCED_GREETING = "/greeting/advanced";
+ private static final String SIMPLE_GREETING = "/greeting/simple";
+ private static final String ADVANCED_GREETING = "/greeting/advanced";
- @Autowired
- private TestRestTemplate restTemplate;
+ @Autowired
+ private TestRestTemplate restTemplate;
- @Test
- public void whenRequestNotExceedingCapacity_thenReturnOkResponse() {
- ResponseEntity response = this.restTemplate.getForEntity(SIMPLE_GREETING, String.class);
- HttpHeaders headers = response.getHeaders();
- String key = "rate-limit-application_serviceSimple_127.0.0.1";
- assertHeaders(headers, key, false, false);
- assertEquals(OK, response.getStatusCode());
- }
+ @Test
+ public void whenRequestNotExceedingCapacity_thenReturnOkResponse() {
+ ResponseEntity response = this.restTemplate.getForEntity(SIMPLE_GREETING, String.class);
+ HttpHeaders headers = response.getHeaders();
+ String key = "rate-limit-application_serviceSimple_127.0.0.1";
- @Test
- public void whenRequestExceedingCapacity_thenReturnTooManyRequestsResponse() throws InterruptedException {
- ResponseEntity response = this.restTemplate
- .getForEntity(ADVANCED_GREETING, String.class);
- HttpHeaders headers = response.getHeaders();
- String key = "rate-limit-application_serviceAdvanced_127.0.0.1";
- assertHeaders(headers, key, false, false);
- assertEquals(OK, response.getStatusCode());
+ String limit = headers.getFirst(HEADER_LIMIT + key);
+ String remaining = headers.getFirst(HEADER_REMAINING + key);
+ String reset = headers.getFirst(HEADER_RESET + key);
- for (int i = 0; i < 2; i++) {
- response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);
+ assertEquals(limit, "5");
+ assertEquals(remaining, "4");
+ assertEquals(reset, "60000");
+
+ assertEquals(OK, response.getStatusCode());
}
- assertEquals(TOO_MANY_REQUESTS, response.getStatusCode());
- assertNotEquals(GreetingController.ADVANCED_RESPONSE, response.getBody());
+ @Test
+ public void whenRequestExceedingCapacity_thenReturnTooManyRequestsResponse() throws InterruptedException {
+ ResponseEntity response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);
+ HttpHeaders headers = response.getHeaders();
+ String key = "rate-limit-application_serviceAdvanced_127.0.0.1";
+ assertHeaders(headers, key, false, false);
+ assertEquals(OK, response.getStatusCode());
- TimeUnit.SECONDS.sleep(2);
+ for (int i = 0; i < 2; i++) {
+ response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);
+ }
- response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);
- headers = response.getHeaders();
- assertHeaders(headers, key, false, false);
- assertEquals(OK, response.getStatusCode());
- }
+ headers = response.getHeaders();
+ String limit = headers.getFirst(HEADER_LIMIT + key);
+ String remaining = headers.getFirst(HEADER_REMAINING + key);
+ String reset = headers.getFirst(HEADER_RESET + key);
- private void assertHeaders(HttpHeaders headers, String key, boolean nullable,
- boolean quotaHeaders) {
- String quota = headers.getFirst(HEADER_QUOTA + key);
- String remainingQuota = headers.getFirst(HEADER_REMAINING_QUOTA + key);
- String limit = headers.getFirst(HEADER_LIMIT + key);
- String remaining = headers.getFirst(HEADER_REMAINING + key);
- String reset = headers.getFirst(HEADER_RESET + key);
+ assertEquals(limit, "1");
+ assertEquals(remaining, "0");
+ assertNotEquals(reset, "2000");
- if (nullable) {
- if (quotaHeaders) {
- assertNull(quota);
- assertNull(remainingQuota);
- } else {
- assertNull(limit);
- assertNull(remaining);
- }
- assertNull(reset);
- } else {
- if (quotaHeaders) {
- assertNotNull(quota);
- assertNotNull(remainingQuota);
- } else {
- assertNotNull(limit);
- assertNotNull(remaining);
- }
- assertNotNull(reset);
+ assertEquals(TOO_MANY_REQUESTS, response.getStatusCode());
+ assertNotEquals(GreetingController.ADVANCED_RESPONSE, response.getBody());
+
+ TimeUnit.SECONDS.sleep(2);
+
+ response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class);
+ headers = response.getHeaders();
+ assertHeaders(headers, key, false, false);
+ assertEquals(OK, response.getStatusCode());
}
- }
+ private void assertHeaders(HttpHeaders headers, String key, boolean nullable, boolean quotaHeaders) {
+ String quota = headers.getFirst(HEADER_QUOTA + key);
+ String remainingQuota = headers.getFirst(HEADER_REMAINING_QUOTA + key);
+ String limit = headers.getFirst(HEADER_LIMIT + key);
+ String remaining = headers.getFirst(HEADER_REMAINING + key);
+ String reset = headers.getFirst(HEADER_RESET + key);
+ if (nullable) {
+ if (quotaHeaders) {
+ assertNull(quota);
+ assertNull(remainingQuota);
+ } else {
+ assertNull(limit);
+ assertNull(remaining);
+ }
+ assertNull(reset);
+ } else {
+ if (quotaHeaders) {
+ assertNotNull(quota);
+ assertNotNull(remainingQuota);
+ } else {
+ assertNotNull(limit);
+ assertNotNull(remaining);
+ }
+ assertNotNull(reset);
+ }
+ }
}