Stop Hammering APIs: Cache Responses with requests-cache
Learn how to use requests-cache to transparently cache API responses, reduce network calls, avoid rate limits, and speed up your Python scripts with just a few lines of code.
Stop Hammering APIs: How to Cache Responses with requests-cache
If you've ever written a Python script that makes the same API call over and over, you already know the pain. Maybe it's a weather endpoint you're polling every minute, or a slow REST service that takes 3 seconds to respond. Each request wastes bandwidth, eats up API rate limits, and makes your code feel sluggish.
The fix? Cache those responses. And the best library for the job is requests-cache.
What does requests-cache actually do?
It's a transparent drop-in wrapper around the popular requests library. Install it, import it, and suddenly every requests.get() call automatically checks a local cache before hitting the network. If the response is in the cache and still fresh, it returns instantly — no network overhead.
Let's see it in action:
import requests_cache
# Enable caching with a SQLite backend
requests_cache.install_cache('api_cache', expire_after=300)
# Now all requests are cached automatically
response = requests.get('https://api.github.com/users/PythonSkillset')
print(response.from_cache) # False first time, True on subsequent calls
The first call fetches from GitHub and stores the result. Every call within the next 5 minutes returns instantly from the SQLite database sitting in your project folder. No more hammering their servers.
Why not just use a dictionary?
You could manually check a dict before making requests. But that approach breaks immediately: - No expiration — your cache grows stale forever - No persistent storage — restart your script and it's gone - No disk-based sharing between runs
requests-cache gives you all this out of the box. It even handles conditional requests (If-Modified-Since headers) so if your cached response is expired but unchanged on the server, it returns the old data with zero data transfer.
Real-world example: Avoiding rate limits
Say you're building a CLI tool that fetches Bitcoin prices from CoinDesk's free API. They allow 10 requests per hour. Without caching, if a user runs your tool twice in 10 minutes, they burn two requests. With caching:
import requests_cache
requests_cache.install_cache('btc_cache', expire_after=3600) # 1 hour cache
def get_btc_price():
response = requests.get('https://api.coindesk.com/v1/bpi/currentprice.json')
data = response.json()
return data['bpi']['USD']['rate']
print(get_btc_price()) # Real request
print(get_btc_price()) # Instant — from cache
print(get_btc_price()) # Still instant — you saved 3 API calls
Your users get lightning-fast responses, and you stay well within rate limits. PythonSkillset readers love this trick when building dashboard apps.
Going further: Custom backends and serialization
SQLite is the default, but you can swap it:
# In-memory cache (fast but volatile)
requests_cache.install_cache('memory', backend='memory')
# Redis backend (share cache across processes)
requests_cache.install_cache('redis_cache', backend='redis', expire_after=600)
For complex scenarios, you can also filter which URLs get cached. Maybe you cache GET but not POST:
def my_filter(response):
return response.request.method == 'GET'
requests_cache.install_cache('filtered_cache', filter_fn=my_filter)
When not to cache
Don't cache raw authentication tokens that expire in 5 minutes. Don't cache user-specific data if multiple users share the same machine. And never cache financial transactions.
But for read-heavy, predictable endpoints? requests-cache is the most elegant solution I've found. It's battle-tested, actively maintained (10k+ GitHub stars), and removes one of the biggest footguns in network programming.
Next time you write a script that calls an API, add two lines at the top. Your code will run faster, your API provider will thank you, and your future self won't have to debug rate-limit errors at 3 AM.
Comments
Questions, corrections, and tips stay visible for everyone reading this page.
Join the discussion
No comments yet
Be the first to leave a note — it helps the next reader.