{"id":67521,"date":"2017-07-17T16:01:17","date_gmt":"2017-07-17T13:01:17","guid":{"rendered":"https:\/\/www.javacodegeeks.com\/?p=67521"},"modified":"2017-07-17T14:03:36","modified_gmt":"2017-07-17T11:03:36","slug":"basic-api-rate-limiting","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html","title":{"rendered":"Basic API Rate-Limiting"},"content":{"rendered":"<p>It is likely that you are developing some form of (web\/RESTful) API, and in case it is publicly-facing (or even when it\u2019s internal), you normally want to rate-limit it somehow. That is, to limit the number of requests performed over a period of time, in order to save resources and protect from abuse.<\/p>\n<p>This can probably be achieved on web-server\/load balancer level with some clever configurations, but usually you want the rate limiter to be client-specific (i.e. each client of your API sohuld have a separate rate limit), and the way the client is identified varies. It\u2019s probably still possible to do it on the load balancer, but I think it makes sense to have it on the application level.<\/p>\n<p>I\u2019ll use spring-mvc for the example, but any web framework has a good way to plug an interceptor.<\/p>\n<p>So here\u2019s an example of a spring-mvc interceptor:<\/p>\n<pre class=\"brush:java\">@Component\r\npublic class RateLimitingInterceptor extends HandlerInterceptorAdapter {\r\n\r\n    private static final Logger logger = LoggerFactory.getLogger(RateLimitingInterceptor.class);\r\n    \r\n    @Value(\"${rate.limit.enabled}\")\r\n    private boolean enabled;\r\n    \r\n    @Value(\"${rate.limit.hourly.limit}\")\r\n    private int hourlyLimit;\r\n\r\n    private Map&lt;String, Optional&lt;SimpleRateLimiter&gt;&gt; limiters = new ConcurrentHashMap&lt;&gt;();\r\n    \r\n    @Override\r\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)\r\n            throws Exception {\r\n        if (!enabled) {\r\n            return true;\r\n        }\r\n        String clientId = request.getHeader(\"Client-Id\");\r\n        \/\/ let non-API requests pass\r\n        if (clientId == null) {\r\n            return true;\r\n        }\r\n        SimpleRateLimiter rateLimiter = getRateLimiter(clientId);\r\n        boolean allowRequest = limiter.tryAcquire();\r\n    \r\n        if (!allowRequest) {\r\n            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());\r\n        }\r\n        response.addHeader(\"X-RateLimit-Limit\", String.valueOf(hourlyLimit));\r\n        return allowRequest;\r\n    }\r\n    \r\n    private SimpleRateLimiter getRateLimiter(String clientId) {\r\n        if (limiters.containsKey(clientId)) {\r\n            return limiters.get(clientId);\r\n        } else {\r\n            synchronized(clientId.intern()) {\r\n                \/\/ double-checked locking to avoid multiple-reinitializations\r\n                if (limiters.containsKey(clientId)) {\r\n                    return limiters.get(clientId);\r\n                }\r\n                \r\n                SimpleRateLimiter rateLimiter = createRateLimiter(clientId);\r\n                \r\n                limiters.put(clientId, rateLimiter);\r\n                return rateLimiter;\r\n            }\r\n        }\r\n    }\r\n\t\r\n\t@PreDestroy\r\n\tpublic void destroy() {\r\n\t\t\/\/ loop and finalize all limiters\r\n\t}\r\n}<\/pre>\n<p>This initializes rate-limiters per client on demand. Alternatively, on startup you could just loop through all registered API clients and create a rate limiter for each. In case the rate limiter doesn\u2019t allow more requests (tryAcquire() returns false), then raturn \u201cToo many requests\u201d and abort the execution of the request (return \u201cfalse\u201d from the interceptor).<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p>This sounds simple. But there are a few catches. You may wonder where the <code>SimpleRateLimiter<\/code> above is defined. We\u2019ll get there, but first let\u2019s see what options do we have for rate limiter implementations.<\/p>\n<p>The most recommended one seems to be the guava <a href=\"https:\/\/google.github.io\/guava\/releases\/22.0\/api\/docs\/index.html?com\/google\/common\/util\/concurrent\/RateLimiter.html\">RateLimiter<\/a>. It has a straightforward factory method that gives you a rate limiter for a specified rate (permits per second). However, it doesn\u2019t accomodate web APIs very well, as you can\u2019t initilize the RateLimiter with pre-existing number of permits. That means a period of time should elapse before the limiter would allow requests. There\u2019s another issue \u2013 if you have less than one permits per second (e.g. if your desired rate limit is \u201c200 requests per hour\u201d), you can pass a fraction (hourlyLimit \/ secondsInHour), but it still won\u2019t work the way you expect it to, as internally there\u2019s a \u201cmaxPermits\u201d field that would cap the number of permits to much less than you want it to. Also, the rate limiter doesn\u2019t allow bursts \u2013 you have exactly X permits per second, but you cannot spread them over a long period of time, e.g. have 5 requests in one second, and then no requests for the next few seconds. In fact, all of the above can be solved, but sadly, through hidden fields that you don\u2019t have access to. Multiple feature requests exist for years now, but Guava just doesn\u2019t update the rate limiter, making it much less applicable to API rate-limiting.<\/p>\n<p>Using reflection, you can tweak the parameters and make the limiter work. However, it\u2019s ugly, and it\u2019s not guaranteed it will work as expected. <a href=\"https:\/\/gist.github.com\/Glamdring\/287844346374297bc0880b06df9dd492\">I have shown here<\/a> how to initialize a guava rate limiter with X permits per hour, with burstability and full initial permits. When I thought that would do, I saw that <code>tryAcquire()<\/code> has a <code>synchronized(..)<\/code> block. Will that mean all requests will wait for each other when simply checking whether allowed to make a request? That would be horrible.<\/p>\n<p>So in fact the guava RateLimiter is not meant for (web) API rate-limiting. Maybe keeping it feature-poor is Guava\u2019s way for discouraging people from misusing it?<\/p>\n<p>That\u2019s why I decided to implement something simple myself, based on a Java Semaphore. <a href=\"https:\/\/gist.github.com\/Glamdring\/06be638d3913c6a23ecf820852ede60b\">Here\u2019s the naive implementation<\/a>:<\/p>\n<pre class=\"brush:java\">public class SimpleRateLimiter {\r\n    private Semaphore semaphore;\r\n    private int maxPermits;\r\n    private TimeUnit timePeriod;\r\n    private ScheduledExecutorService scheduler;\r\n\r\n    public static SimpleRateLimiter create(int permits, TimeUnit timePeriod) {\r\n        SimpleRateLimiter limiter = new SimpleRateLimiter(permits, timePeriod);\r\n        limiter.schedulePermitReplenishment();\r\n        return limiter;\r\n    }\r\n\r\n    private SimpleRateLimiter(int permits, TimeUnit timePeriod) {\r\n        this.semaphore = new Semaphore(permits);\r\n        this.maxPermits = permits;\r\n        this.timePeriod = timePeriod;\r\n    }\r\n\r\n    public boolean tryAcquire() {\r\n        return semaphore.tryAcquire();\r\n    }\r\n\r\n    public void stop() {\r\n        scheduler.shutdownNow();\r\n    }\r\n\r\n    public void schedulePermitReplenishment() {\r\n        scheduler = Executors.newScheduledThreadPool(1);\r\n        scheduler.schedule(() -&gt; {\r\n            semaphore.release(maxPermits - semaphore.availablePermits());\r\n        }, 1, timePeriod);\r\n\r\n    }\r\n}<\/pre>\n<p>It takes a number of permits (allowed number of requests) and a time period. The time period is \u201c1 X\u201d, where X can be second\/minute\/hour\/daily \u2013 depending on how you want your limit to be configured \u2013 per second, per minute, hourly, daily. Every 1 X a scheduler replenishes the acquired permits. There is no control for bursts (a client can spend all permits with a rapid succession of requests), there is no warm-up functionality, there is no gradual replenishment. Depending on what you want, this may not be ideal, but that\u2019s just a basic rate limiter that is thread-safe and doesn\u2019t have any blocking. I wrote a unit test to confirm that the limiter behaves properly, and also ran performance tests against a local application to make sure the limit is obeyed. So far it seems to be working.<\/p>\n<p>Are there alternatives? Well, yes \u2013 there are libraries like <a href=\"https:\/\/github.com\/mokies\/ratelimitj\">RateLimitJ<\/a> that uses Redis to implement rate-limiting. That would mean, however, that you need to setup and run Redis. Which seems like an overhead for \u201csimply\u201d having rate-limiting.<\/p>\n<p>On the other hand, how would rate-limiting work properly in a cluster of application nodes? Application nodes probably need some database or gossip protocol to share data about the per-client permits (requests) remaining? Not necessarily. A very simple approach to this issue would be to assume that the load balancer distributes the load equally among your nodes. That way you would just have to set the limit on each node to be equal to the total limit divided by the number of nodes. It won\u2019t be exact, but you rarely need it to be \u2013 allowing 5-10 more requests won\u2019t kill your application, allowing 5-10 less won\u2019t be dramatic for the users.<\/p>\n<p>That, however, would mean that you have to know the number of application nodes. If you employ auto-scaling (e.g. in AWS), the number of nodes may change depending on the load. If that is the case, instead of configuring a hard-coded number of permits, the replenishing scheduled job can calculate the \u201cmaxPermits\u201d on the fly, by calling an AWS (or other cloud-provider) API to obtain the number of nodes in the current auto-scaling group. That would still be simpler than supporting a redis deployment just for that.<\/p>\n<p>Overall, I\u2019m surprised there isn\u2019t a \u201ccanonical\u201d way to implement rate-limiting (in Java). Maybe the need for rate-limiting is not as common as it may seem. Or it\u2019s implemented manually \u2013 by temporarily banning API clients that use \u201ctoo much resources\u201d.<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td><span class=\"reference\">Reference: <\/span><\/td>\n<td><a href=\"https:\/\/techblog.bozho.net\/basic-api-rate-limiting\/\">Basic API Rate-Limiting<\/a> from our <a href=\"http:\/\/www.javacodegeeks.com\/join-us\/jcg\/\">JCG partner<\/a> Bozhidar Bozhanov at the <a href=\"http:\/\/techblog.bozho.net\/\">Bozho&#8217;s tech blog<\/a> blog.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>It is likely that you are developing some form of (web\/RESTful) API, and in case it is publicly-facing (or even when it\u2019s internal), you normally want to rate-limit it somehow. That is, to limit the number of requests performed over a period of time, in order to save resources and protect from abuse. This can &hellip;<\/p>\n","protected":false},"author":55,"featured_media":112,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-67521","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Basic API Rate-Limiting - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"It is likely that you are developing some form of (web\/RESTful) API, and in case it is publicly-facing (or even when it\u2019s internal), you normally want to\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Basic API Rate-Limiting - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"It is likely that you are developing some form of (web\/RESTful) API, and in case it is publicly-facing (or even when it\u2019s internal), you normally want to\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2017-07-17T13:01:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Bozhidar Bozhanov\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Bozhidar Bozhanov\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html\"},\"author\":{\"name\":\"Bozhidar Bozhanov\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/1eaacbb8d159c99fd32e6b51198a1e79\"},\"headline\":\"Basic API Rate-Limiting\",\"datePublished\":\"2017-07-17T13:01:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html\"},\"wordCount\":1033,\"commentCount\":3,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html\",\"name\":\"Basic API Rate-Limiting - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"datePublished\":\"2017-07-17T13:01:17+00:00\",\"description\":\"It is likely that you are developing some form of (web\\\/RESTful) API, and in case it is publicly-facing (or even when it\u2019s internal), you normally want to\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"java-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/07\\\/basic-api-rate-limiting.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Basic API Rate-Limiting\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/1eaacbb8d159c99fd32e6b51198a1e79\",\"name\":\"Bozhidar Bozhanov\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/12\\\/bozhidar.bozhanov.jpg\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/12\\\/bozhidar.bozhanov.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/12\\\/bozhidar.bozhanov.jpg\",\"caption\":\"Bozhidar Bozhanov\"},\"description\":\"Senior Java developer, one of the top stackoverflow users, fluent with Java and Java technology stacks - Spring, JPA, JavaEE, as well as Android, Scala and any framework you throw at him. creator of Computoser - an algorithmic music composer. Worked on telecom projects, e-government and large-scale online recruitment and navigation platforms.\",\"sameAs\":[\"http:\\\/\\\/techblog.bozho.net\\\/\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/bozhidar-bozhanov\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Basic API Rate-Limiting - Java Code Geeks","description":"It is likely that you are developing some form of (web\/RESTful) API, and in case it is publicly-facing (or even when it\u2019s internal), you normally want to","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html","og_locale":"en_US","og_type":"article","og_title":"Basic API Rate-Limiting - Java Code Geeks","og_description":"It is likely that you are developing some form of (web\/RESTful) API, and in case it is publicly-facing (or even when it\u2019s internal), you normally want to","og_url":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2017-07-17T13:01:17+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","type":"image\/jpeg"}],"author":"Bozhidar Bozhanov","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Bozhidar Bozhanov","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html"},"author":{"name":"Bozhidar Bozhanov","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/1eaacbb8d159c99fd32e6b51198a1e79"},"headline":"Basic API Rate-Limiting","datePublished":"2017-07-17T13:01:17+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html"},"wordCount":1033,"commentCount":3,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html","url":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html","name":"Basic API Rate-Limiting - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","datePublished":"2017-07-17T13:01:17+00:00","description":"It is likely that you are developing some form of (web\/RESTful) API, and in case it is publicly-facing (or even when it\u2019s internal), you normally want to","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","width":150,"height":150,"caption":"java-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2017\/07\/basic-api-rate-limiting.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Basic API Rate-Limiting"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/1eaacbb8d159c99fd32e6b51198a1e79","name":"Bozhidar Bozhanov","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/12\/bozhidar.bozhanov.jpg","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/12\/bozhidar.bozhanov.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/12\/bozhidar.bozhanov.jpg","caption":"Bozhidar Bozhanov"},"description":"Senior Java developer, one of the top stackoverflow users, fluent with Java and Java technology stacks - Spring, JPA, JavaEE, as well as Android, Scala and any framework you throw at him. creator of Computoser - an algorithmic music composer. Worked on telecom projects, e-government and large-scale online recruitment and navigation platforms.","sameAs":["http:\/\/techblog.bozho.net\/"],"url":"https:\/\/www.javacodegeeks.com\/author\/bozhidar-bozhanov"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/67521","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/55"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=67521"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/67521\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/112"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=67521"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=67521"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=67521"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}