Rate limits are a curse to API consumers and a blessing to API developers.
Some APIs even have different limits for different endpoints.
Of course, if we are just calling one endpoint multiple times, we can simply debounce or throttle the call.
However, it can get tricky when we are triggering multiple calls to different endpoints after calling one endpoint.
Plus, debounce is so 2013; we are in 2018 already.
So today, I’d like to present a declarative way of working around rate limits as API consumers.
Hopefully, this makes consuming rate limited APIs easier while at the same time keeping API developers and DevOps people happy.
What is async/await
Let’s take a look at how async/await works first.
Note: for those of you who already understand this, please close this tab and stop looking at my embarrassing explanation below.
Here’s a code snippet to illustrate it more clearly:
As you can see, Promises already help reduce some levels of nesting.
async/await takes it to a whole new level.
I’ll give you a moment to appreciate this amazing technological advancement.
Now, we can do some cool things with this, such as putting a delay before API calls in a declarative way, like this:
Please do try this at home.
Using async/await in a loop
You might be so excited about
async/await right now that you want to attempt to use it in a for-loop.
Take a guess what the following snippet does:
If your guess is that each index will be logged out with a one-second delay in between, then you’ve guessed wrong. Go ahead, try it in the devtools console.
Properly using async/await in a loop
To use the
async/await delay helper in a loop, we will need to use another new ECMAScript feature (ES2015 to be exact) to make it work: the
Here’s an example:
The index of each list item will now be logged out with a one-second delay between each other.
Applying to rate limited API calls
Now that we have figured out how to use
async/await in a loop, we can apply this to work around rate limited calls.
I have written a delayed map helper to make it even easier:
And here’s an example usage of the helper:
I hope by now you are convinced that
async/await can help clarify your code by making it more readable and declarative.
There are also other benefits I haven’t touched on in this article, such as the ability to catch errors with the more primitive
try..catch block instead of relying on the one provided with the Promise API (which actually is also becoming a primitive…).
But, relying ES2015 and ES2017 features does mean that required transpilation step (e.g. with BabelJS) is required for them to work in all browsers (works in most modern browsers though).
And honestly, debounce or throttle is sufficient for most cases.
In a word, it’s nice to live on the cutting edge, but in some cases it might be good to play safe and stick with the older and not-so-cool ways of doing things.