The HTTP caching Python deserves

1 month ago 41

What My Project Does

Hishel is an HTTP caching toolkit for python, which includes sans-io caching implementation, storages for effectively storing request/response for later use, and integration with your lovely HTTP tool in python such as HTTPX, requests, fastapi, asgi (for any asgi based library), graphql and more!!

Hishel uses persistent storage by default, so your cached responses survive program restarts.

After 2 years and over 63 MILLION pip installs, I released the first major version with tons of new features to simplify caching.

✨ Help Hishel grow! Give us a star on GitHub if you found it useful. ✨

Use Cases:

HTTP response caching is something you can use almost everywhere to:

  • Improve the performance of your program
  • Work without an internet connection (offline mode)
  • Save money and stop wasting API calls—make a single request and reuse it many times!
  • Work even when your upstream server goes down
  • Avoid unnecessary downloads when content hasn't changed (what I call "free caching"—it's completely free and can be configured to always serve the freshest data without re-downloading if nothing changed, like the browser's 304 Not Modified response)

QuickStart

First, download and install Hishel using pip:

pip: pip install "hishel[httpx, requests, fastapi, async]"==1.0.0

We've installed several integrations just for demonstration—you most likely won't need them all.

from hishel.httpx import SyncCacheClient client = SyncCacheClient() # On first run of the program, this will store the response in the cache # On second run, it will retrieve it from the cache response = client.get("https://hishel.com/") print(response.extensions["hishel_from_cache"]) # Additional info about the cache statusfrom hishel.httpx import SyncCacheClient client = SyncCacheClient() # On first run of the program, this will store the response in the cache # On second run, it will retrieve it from the cache response = client.get("https://hishel.com/") print(response.extensions["hishel_from_cache"]) # Additional info about the cache status

or with requests:

import requests from hishel.requests import CacheAdapter session = requests.Session() adapter = CacheAdapter() session.mount("http://", adapter) session.mount("https://", adapter) response = session.get("https://hishel.com/") print(response.headers["x-hishel-from-cache"])

or with fastapi:

from hishel.asgi import ASGICacheMiddleware from hishel.fastapi import cache app = FastAPI() processed_requests = 0 .get("/items/", dependencies=[cache(max_age=5)]) async def read_item(): global processed_requests processed_requests += 1 return {"created_at": time.time(), "processed_requests": processed_requests} cached_app = ASGICacheMiddleware(app)

As mentioned before, Hishel has a core system that is entirely independent from any HTTP library, making it easy to integrate with any HTTP client you prefer.

Caching Policies

SpecificationPolicy - RFC 9111 compliant HTTP caching (default):

from hishel import CacheOptions, SpecificationPolicy from hishel.httpx import SyncCacheClient client = SyncCacheClient( policy=SpecificationPolicy( cache_options=CacheOptions( shared=False, # Use as private cache (browser-like) supported_methods=["GET", "HEAD", "POST"], # Cache GET, HEAD, and POST allow_stale=True # Allow serving stale responses ) ) )

FilterPolicy - Custom filtering logic for fine-grained control:

from hishel import FilterPolicy, BaseFilter, Request from hishel.httpx import AsyncCacheClient class CacheOnlyAPIRequests(BaseFilter[Request]): def needs_body(self) -> bool: return False def apply(self, item: Request, body: bytes | None) -> bool: return "/api/" in str(item.url) client = AsyncCacheClient( policy=FilterPolicy( request_filters=[CacheOnlyAPIRequests()] # also filter by body, status and etc. ) )

Storage Backend

Customize the storage backend behavior, set up global TTL (note that TTL and most settings can also be configured at the per-request level), choose whether to refresh TTL on access, and much more!

from hishel import SyncSqliteStorage from hishel.httpx import SyncCacheClient storage = SyncSqliteStorage( database_path="my_cache.db", default_ttl=7200.0, # Cache entries expire after 2 hours refresh_ttl_on_access=True # Reset TTL when accessing cached entries ) client = SyncCacheClient(storage=storage)

Per-request settings

from hishel.httpx import SyncCacheClient client = SyncCacheClient() client.get( "https://hishel.com/", headers={ "x-hishel-ttl": "3600", # invalidates cache after 1 hour, even if server says otherwise }, ) client.post( "https://some-graphql-endpoint.com/", json={"query": "{ users { id name } }"}, headers={"x-hishel-body-key"}, # Include body in cache key ) client.get( "https://hishel.com/", headers={"x-hishel-refresh-ttl-on-access": "0"} # do not refresh TTL on access )

Target Audience

Backend Developers - Building APIs with FastAPI/Django, making repeated HTTP requests to external APIs

Data Engineers - Running ETL pipelines and batch jobs, fetching same data across multiple runs

CLI Tool Builders - Creating command-line tools, need instant responses and offline support

Web Scrapers - Building content crawlers, respect rate limits and need offline testing

API Library Maintainers - Wrapping external APIs (GitHub, Stripe, OpenAI), need transparent caching

GraphQL Developers - Need per-query caching with body-sensitive keys

Also great for: DevOps teams, performance-focused companies, enterprise users needing RFC 9111 compliance

⭐ GitHub: https://github.com/karpetrosyan/hishelWhat

submitted by /u/karosis88 to r/Python
[link] [comments]
Read Entire Article