### Install Hishel using pip Source: https://github.com/karpetrosyan/hishel/blob/master/docs/quickstart.md Install the Hishel library using pip. This is the first step before using any of its features. ```bash pip install hishel ``` -------------------------------- ### Install Zapros with Caching Support Source: https://github.com/karpetrosyan/hishel/blob/master/docs/zapros.md Install Zapros with the necessary caching dependencies. ```bash pip install zapros[caching] ``` -------------------------------- ### Install Dependencies with uv Source: https://github.com/karpetrosyan/hishel/blob/master/docs/contributing.md Install project dependencies using uv, ensuring all extras and development dependencies are included. ```bash uv sync --all-extras --dev ``` -------------------------------- ### Quick Start with SyncCacheClient Source: https://github.com/karpetrosyan/hishel/blob/master/docs/httpx.md Use SyncCacheClient for synchronous applications. The first request fetches from the origin, while subsequent identical requests are served from the cache. ```python from hishel.httpx import SyncCacheClient client = SyncCacheClient() # First request - fetches from origin response = client.get("https://api.example.com/data") print(response.extensions["hishel_from_cache"]) # False # Second request - served from cache response = client.get("https://api.example.com/data") print(response.extensions["hishel_from_cache"]) # True ``` -------------------------------- ### Async to Sync Code Transformation Example Source: https://github.com/karpetrosyan/hishel/blob/master/docs/contributing.md Illustrates the transformation of an async function to its synchronous equivalent by the unasync script. ```python # Async code (you write this) async def store(self, key: str) -> None: async with self.connection as conn: await conn.execute(...) # Sync code (automatically generated) def store(self, key: str) -> None: with self.connection as conn: conn.execute(...) ``` -------------------------------- ### Install Hishel for FastAPI Source: https://github.com/karpetrosyan/hishel/blob/master/docs/fastapi.md Install Hishel with FastAPI support using pip. If FastAPI is already installed, install only Hishel. ```bash pip install hishel[fastapi] ``` ```bash pip install hishel ``` -------------------------------- ### Quick Start with AsyncCacheClient Source: https://github.com/karpetrosyan/hishel/blob/master/docs/httpx.md Use AsyncCacheClient for asynchronous applications. The first request fetches from the origin, while subsequent identical requests are served from the cache. ```python from hishel.httpx import AsyncCacheClient async with AsyncCacheClient() as client: # First request - fetches from origin response = await client.get("https://api.example.com/data") print(response.extensions["hishel_from_cache"]) # False # Second request - served from cache response = await client.get("https://api.example.com/data") print(response.extensions["hishel_from_cache"]) # True ``` -------------------------------- ### Configure SpecificationPolicy Supported Methods Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Define which HTTP methods are cacheable using 'supported_methods' in CacheOptions. Defaults to GET and HEAD. ```python # Default: cache GET and HEAD only policy = SpecificationPolicy( cache_options=CacheOptions( supported_methods=["GET", "HEAD"] ) ) ``` ```python # Cache POST responses (advanced use case) policy = SpecificationPolicy( cache_options=CacheOptions( supported_methods=["GET", "HEAD", "POST"] ) ) ``` -------------------------------- ### Get Cache Entry Creation Time (requests) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Access the `X-Hishel-Created-At` header to get the POSIX timestamp of when the cache entry was created. This is useful for logging and calculating remaining freshness. ```python created = response.headers.get("X-Hishel-Created-At") if created: print("Cached at:", created) ``` -------------------------------- ### Quick Start: Add Cache to Requests Session Source: https://github.com/karpetrosyan/hishel/blob/master/docs/requests.md Mount the CacheAdapter to your Requests session to enable HTTP caching. The first request fetches from the origin, while subsequent identical requests are served from the cache. ```python import requests from hishel.requests import CacheAdapter # Create session with cache adapter session = requests.Session() session.mount("https://", CacheAdapter()) session.mount("http://", CacheAdapter()) # First request - fetches from origin response = session.get("https://api.example.com/data") print(response.headers.get("X-Hishel-From-Cache")) # None # Second request - served from cache response = session.get("https://api.example.com/data") print(response.headers.get("X-Hishel-From-Cache")) # True ``` -------------------------------- ### Get Cache Entry Creation Time (httpx) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Retrieve the POSIX timestamp of when the cache entry was created using `response.extensions.get('hishel_created_at')`. This can be used to calculate the remaining Time To Live (TTL). ```python created = response.extensions.get("hishel_created_at") if created: print("Cached at:", created) ``` -------------------------------- ### Use SpecificationPolicy with Requests CacheAdapter Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Adapt SpecificationPolicy for use with the 'requests' library by mounting a CacheAdapter to a requests.Session. This example configures a private cache. ```python import requests from hishel.requests import CacheAdapter from hishel import SpecificationPolicy, CacheOptions policy = SpecificationPolicy( cache_options=CacheOptions(shared=False) ) session = requests.Session() session.mount("https://", CacheAdapter(policy=policy)) session.mount("http://", CacheAdapter(policy=policy)) response = session.get("https://api.example.com/data") ``` -------------------------------- ### Cache API routes in BlackSheep Source: https://github.com/karpetrosyan/hishel/blob/master/docs/quickstart.md Apply caching to BlackSheep API endpoints using the @cache_control decorator. This example caches responses for 5 minutes, making them public. ```python from blacksheep import Application, get from blacksheep.server.headers.cache import cache_control app = Application() @get("/api/data") @cache_control(max_age=300, public=True) async def get_data(): # Cache-Control: public, max-age=300 return {"data": "cached for 5 minutes"} ``` -------------------------------- ### Cache API routes in FastAPI Source: https://github.com/karpetrosyan/hishel/blob/master/docs/quickstart.md Use Hishel's cache decorator to cache responses from FastAPI routes. This example caches responses for 5 minutes and marks them as public. ```python from fastapi import FastAPI from hishel import AsyncSqliteStorage from hishel.fastapi import cache from hishel.asgi import ASGICacheMiddleware app = FastAPI() @app.get("/api/data", dependencies=[cache(max_age=300, public=True)]) async def get_data(): # Cache-Control: public, max-age=300 return {"data": "cached for 5 minutes"} app = ASGICacheMiddleware(app, storage=AsyncSqliteStorage()) ``` -------------------------------- ### Instantiate SyncCacheClient Source: https://github.com/karpetrosyan/hishel/blob/master/docs/httpx.md Create a SyncCacheClient with default settings for synchronous HTTP requests. It can be used like a standard httpx.Client. ```python from hishel.httpx import SyncCacheClient # Create client with default settings client = SyncCacheClient() # Make requests as usual response = client.get("https://api.example.com/users") ``` -------------------------------- ### Initialize Sync and Async Redis Storage Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Instantiate the synchronous or asynchronous Redis storage using a Redis client. This backend uses a Redis server for caching. ```python from redis import Redis from hishel import RedisStorage client = Redis(host="localhost", port=6379) storage = RedisStorage(client=client) ``` ```python from redis.asyncio import Redis from hishel import AsyncRedisStorage client = Redis(host="localhost", port=6379) storage = AsyncRedisStorage(client=client) ``` -------------------------------- ### Initialize AsyncCacheProxy with Policy Source: https://github.com/karpetrosyan/hishel/blob/master/docs/proxies.md Configure AsyncCacheProxy with a custom policy to control which requests are cached. The policy is passed as an argument during initialization. ```python from hishel import AsyncCacheProxy, FilterPolicy async_cache_proxy = AsyncCacheProxy( lambda request: send_request(request), policy=FilterPolicy(), ) response = async_cache_proxy.handle_request(Request(...)) ``` -------------------------------- ### Initialize AsyncCacheProxy Source: https://github.com/karpetrosyan/hishel/blob/master/docs/proxies.md Instantiate AsyncCacheProxy with a callable to fetch origin responses. This callable will be invoked when a cache miss occurs. ```python from hishel import AsyncCacheProxy, Request async_cache_proxy = AsyncCacheProxy(lambda request: send_request(request)) response = async_cache_proxy.handle_request(Request(...)) ``` -------------------------------- ### Initialize Sync and Async SQLite Storage Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Instantiate the default synchronous or asynchronous SQLite storage. This storage uses a local SQLite database file for caching. ```python from hishel import SyncSqliteStorage storage = SyncSqliteStorage() ``` ```python from hishel import AsyncSqliteStorage storage = AsyncSqliteStorage() ``` -------------------------------- ### Basic CacheAdapter Usage with Requests Source: https://github.com/karpetrosyan/hishel/blob/master/docs/requests.md Instantiate and mount the CacheAdapter for both HTTP and HTTPS protocols on a Requests session. All standard HTTP methods are supported. ```python import requests from hishel.requests import CacheAdapter # Create a session session = requests.Session() # Mount cache adapter for HTTP and HTTPS adapter = CacheAdapter() session.mount("https://", adapter) session.mount("http://", adapter) # Make requests as usual response = session.get("https://api.example.com/users") # All requests methods work session.post("https://api.example.com/data", json={"key": "value"}) session.put("https://api.example.com/resource/1", data="content") # Close when done session.close() ``` -------------------------------- ### Zapros Synchronous Client with Caching Source: https://github.com/karpetrosyan/hishel/blob/master/docs/zapros.md Demonstrates using Zapros's synchronous client with the CacheMiddleware to enable HTTP caching. The caching status is available in the response context. ```python from zapros import Client, CacheMiddleware, StdNetworkHandler client = Client(handler=CacheMiddleware(StdNetworkHandler())) response = client.get("https://api.example.com/data") print(response.context.get("caching")) # {'from_cache': False, ...} response = client.get("https://api.example.com/data") print(response.context.get("caching")) # {'from_cache': True, ...} ``` -------------------------------- ### Create Git Tag for Release Source: https://github.com/karpetrosyan/hishel/blob/master/docs/contributing.md Create a Git tag for the new release version. ```bash git tag 1.1.6 ``` -------------------------------- ### Initialize IdleClient State Source: https://github.com/karpetrosyan/hishel/blob/master/docs/sans-io.md Create the initial state for the Hishel state machine. This is the only state you should manually instantiate. ```python from hishel import IdleClient state = IdleClient() ``` -------------------------------- ### Zapros Asynchronous Client with Caching Source: https://github.com/karpetrosyan/hishel/blob/master/docs/zapros.md Demonstrates using Zapros's asynchronous client with the CacheMiddleware for HTTP caching. The caching status is available in the response context. ```python from zapros import AsyncClient, CacheMiddleware, AsyncStdNetworkHandler client = AsyncClient(handler=CacheMiddleware(AsyncStdNetworkHandler())) response = await client.get("https://api.example.com/data") print(response.context.get("caching")) # {'from_cache': False, ...} response = await client.get("https://api.example.com/data") print(response.context.get("caching")) # {'from_cache': True, ...} ``` -------------------------------- ### Instantiate AsyncCacheClient Source: https://github.com/karpetrosyan/hishel/blob/master/docs/httpx.md Create an AsyncCacheClient with default settings for asynchronous HTTP requests. It can be used like a standard httpx.AsyncClient. ```python from hishel.httpx import AsyncCacheClient # Create client with default settings client = AsyncCacheClient() # Make requests as usual response = await client.get("https://api.example.com/users") ``` -------------------------------- ### Use Hishel with HTTPX (Async) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/quickstart.md Integrate Hishel's caching with the asynchronous HTTPX client. The first request fetches from the origin, while subsequent identical requests are served from the cache. ```python from hishel.httpx import AsyncCacheClient async with AsyncCacheClient() as client: # First request - fetches from origin await client.get("https://hishel.com") # Second request - served from cache response = await client.get("https://hishel.com") print(response.text) ``` -------------------------------- ### Run Utility Scripts Source: https://github.com/karpetrosyan/hishel/blob/master/docs/contributing.md Execute utility scripts for fixing code style, linting, and running tests with coverage. ```bash ./scripts/fix ``` ```bash ./scripts/lint ``` ```bash ./scripts/test ``` -------------------------------- ### Configure FilterPolicy with Custom Filters Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Initialize FilterPolicy by providing lists of custom request and response filters to implement specific caching logic. ```python from hishel import FilterPolicy, BaseFilter policy = FilterPolicy( request_filters=[...], # List of request filters response_filters=[...], # List of response filters ) ``` -------------------------------- ### Generate Changelog Source: https://github.com/karpetrosyan/hishel/blob/master/docs/contributing.md Use `git cliff` to generate the changelog for the new release, specifying the version range and output file. ```bash git cliff --output CHANGELOG.md 0.1.3.. --tag 1.1.6 ``` -------------------------------- ### Clone Repository and Create Branch Source: https://github.com/karpetrosyan/hishel/blob/master/docs/contributing.md Clone the Hishel repository and create a new branch for your feature development. ```bash git clone https://github.com/username/hishel cd hishel git switch -c my-feature-name ``` -------------------------------- ### Use Hishel with requests Source: https://github.com/karpetrosyan/hishel/blob/master/docs/quickstart.md Integrate Hishel's caching with the synchronous requests library. Mount the CacheAdapter to your session to enable caching for all requests made through that session. ```python import requests from hishel.requests import CacheAdapter session = requests.Session() session.mount("https://", CacheAdapter()) session.mount("http://", CacheAdapter()) # First request - fetches from origin response = session.get("https://hishel.com") # Second request - served from cache response = session.get("https://hishel.com") ``` -------------------------------- ### FastAPI Full Caching with ASGI Middleware Source: https://github.com/karpetrosyan/hishel/blob/master/docs/fastapi.md Combine the `cache()` dependency with `ASGICacheMiddleware` for local server-side caching in addition to client-side caching via Cache-Control headers. ```python from fastapi import FastAPI from hishel.fastapi import cache from hishel.asgi import ASGICacheMiddleware from hishel import AsyncSqliteStorage app = FastAPI() @app.get("/api/data", dependencies=[cache(max_age=300, public=True)]) async def get_data(): # Cached locally AND by clients/CDNs return {"data": "Expensive operation result"} # Wrap with caching middleware to enable local caching app = ASGICacheMiddleware( app, storage=AsyncSqliteStorage(), ) ``` -------------------------------- ### Push Commits and Tags to GitHub Source: https://github.com/karpetrosyan/hishel/blob/master/docs/contributing.md Push both the new commits and the release tags to the GitHub repository. ```bash git push git push --tags ``` -------------------------------- ### CDN Optimization with s-maxage Source: https://github.com/karpetrosyan/hishel/blob/master/docs/fastapi.md Optimize caching for both browsers and CDNs by specifying different cache times using `max_age` for browsers and `s_maxage` for CDNs. ```python @app.get("/api/data", dependencies=[cache( max_age=60, # Browsers: 1 minute s_maxage=3600, # CDN: 1 hour public=True )]) async def get_data(): return {"data": "..."} ``` -------------------------------- ### Transition State with Request Source: https://github.com/karpetrosyan/hishel/blob/master/docs/sans-io.md Advance the state machine by calling the `next` method with a `Request` object and associated entries. The method returns the next state, which could be `CacheMiss`, `FromCache`, or `NeedRevalidation`. ```python from hishel import IdleClient, Request state = IdleClient() request = Request(...) next_state = state.next(request, associated_entries=[]) ``` -------------------------------- ### Generate Sync Code with unasync Source: https://github.com/karpetrosyan/hishel/blob/master/docs/contributing.md Use the unasync script to generate synchronous code from asynchronous code. Use --check to verify if sync files are up-to-date. ```bash ./scripts/unasync ``` ```bash ./scripts/unasync --check ``` -------------------------------- ### Configure SpecificationPolicy with CacheOptions Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Instantiate SpecificationPolicy with CacheOptions to control shared cache behavior, staleness, and supported methods. ```python from hishel import CacheOptions, SpecificationPolicy policy = SpecificationPolicy( cache_options=CacheOptions( shared=True, # Act as a shared cache (proxy/CDN) allow_stale=False, # Don't serve stale responses supported_methods=["GET", "HEAD"], # Cache these methods ) ) ``` -------------------------------- ### Requests Session with CacheAdapter using Context Manager Source: https://github.com/karpetrosyan/hishel/blob/master/docs/requests.md Utilize a Requests session with the CacheAdapter within a context manager for automatic session handling. This ensures the session is properly closed. ```python import requests from hishel.requests import CacheAdapter with requests.Session() as session: session.mount("https://", CacheAdapter()) session.mount("http://", CacheAdapter()) response = session.get("https://api.example.com/data") print(response.json()) ``` -------------------------------- ### Combine Multiple Filters Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Demonstrates combining multiple request and response filters into a single `FilterPolicy`. Filters are applied sequentially, and all request filters must pass for the request to be considered for caching, while all response filters must pass for the response to be cached. ```python from hishel import FilterPolicy policy = FilterPolicy( request_filters=[ URLPatternFilter(r'/api/.*'), MethodFilter(["GET", "HEAD"]), ], response_filters=[ StatusCodeFilter([200, 203, 204, 300, 301, 304, 404, 405, 410]), ContentTypeFilter(["application/json"]), SizeFilter(max_size=1024 * 1024), # Max 1MB ] ) ``` -------------------------------- ### Configure Custom Path for SQLite Storage Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Specify a custom file path for the SQLite database. If not provided, a default path within the current working directory is used. ```python from hishel import SyncSqliteStorage storage = SyncSqliteStorage(database_path="/path/to/cache.db") ``` ```python from hishel import AsyncSqliteStorage storage = AsyncSqliteStorage(database_path="/path/to/cache.db") ``` -------------------------------- ### Integrate SyncCacheTransport with HTTPX Client Source: https://github.com/karpetrosyan/hishel/blob/master/docs/httpx.md Use SyncCacheTransport to add caching to an existing httpx.Client. This requires specifying the next transport and a storage backend like SyncSqliteStorage. ```python import httpx from hishel import SyncSqliteStorage from hishel.httpx import SyncCacheTransport # Create transport with caching transport = SyncCacheTransport( next_transport=httpx.HTTPTransport(), storage=SyncSqliteStorage(), ) # Use with standard HTTPX client client = httpx.Client(transport=transport) response = client.get("https://api.example.com/data") ``` -------------------------------- ### Enable Sliding Expiration with httpx Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Set `hishel_refresh_ttl_on_access` to `True` via extensions to reset the TTL on each access, keeping frequently accessed entries fresh. This enables sliding expiration. ```python from hishel.httpx import SyncCacheClient client = SyncCacheClient() response = client.get( "https://api.example.com/user/profile", extensions={"hishel_refresh_ttl_on_access": True} ) ``` -------------------------------- ### Cache Static Assets in FastAPI Source: https://github.com/karpetrosyan/hishel/blob/master/docs/fastapi.md Configure long cache times for static assets like images using `max_age` and `immutable=True` in the `cache()` dependency. ```python @app.get("/static/logo.png", dependencies=[cache(max_age=31536000, public=True, immutable=True)]) async def get_logo(): return {"file": "logo.png"} ``` -------------------------------- ### Configure Max Stream Size for Redis Storage (Sync) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Limit the maximum size of a response body streamed to Redis to prevent excessive memory usage. Set to None to disable the cap. Defaults to 10 MiB. ```python from redis import Redis from hishel import RedisStorage client = Redis(host="localhost", port=6379) storage = RedisStorage(client=client, max_stream_size=50 * 1024 * 1024) ``` -------------------------------- ### Configure Soft-Delete TTL for Redis Storage (Sync) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Set a custom TTL for soft-deleted entries in Redis. This ensures concurrent requests can complete before data is permanently removed. Defaults to 180 seconds. ```python from redis import Redis from hishel import RedisStorage client = Redis(host="localhost", port=6379) storage = RedisStorage(client=client, soft_delete_ttl=60) ``` -------------------------------- ### Enable Sliding Expiration with requests Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Set the `X-Hishel-Refresh-Ttl-On-Access` header to `"true"` to reset the TTL on each access, keeping frequently accessed entries fresh. This enables sliding expiration. ```python import requests from hishel.requests import CacheAdapter session = requests.Session() session.mount("http://", CacheAdapter()) session.mount("https://", CacheAdapter()) response = session.get( "https://api.example.com/user/profile", headers={"X-Hishel-Refresh-Ttl-On-Access": "true"} ) ``` -------------------------------- ### Configure Soft-Delete TTL for Redis Storage (Async) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Set a custom TTL for soft-deleted entries in Redis using an asynchronous client. This ensures concurrent requests can complete before data is permanently removed. Defaults to 180 seconds. ```python from redis.asyncio import Redis from hishel import AsyncRedisStorage client = Redis(host="localhost", port=6379) storage = AsyncRedisStorage(client=client, soft_delete_ttl=60) ``` -------------------------------- ### Check if Response Was Served From Cache (httpx) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Use `response.extensions.get('hishel_from_cache')` to determine if the response was retrieved from the cache. This is useful for monitoring cache hit rates and debugging. ```python from hishel.httpx import SyncCacheClient client = SyncCacheClient() response = client.get("https://api.example.com/data") if response.extensions.get("hishel_from_cache"): print("✓ Cache hit") else: print("✗ Cache miss - fetched from origin") ``` -------------------------------- ### Integrate AsyncCacheTransport with HTTPX Client Source: https://github.com/karpetrosyan/hishel/blob/master/docs/httpx.md Use AsyncCacheTransport to add caching to an existing httpx.AsyncClient. This requires specifying the next transport and an asynchronous storage backend like AsyncSqliteStorage. ```python import httpx from hishel import AsyncSqliteStorage from hishel.httpx import AsyncCacheTransport # Create transport with caching transport = AsyncCacheTransport( next_transport=httpx.AsyncHTTPTransport(), storage=AsyncSqliteStorage(), ) # Use with standard HTTPX client client = httpx.AsyncClient(transport=transport) response = await client.get("https://api.example.com/data") ``` -------------------------------- ### Create Custom Response Filter Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Create a custom filter for responses by inheriting from BaseFilter[Response]. Implement `needs_body` to specify if the response body is needed and `apply` for the filtering logic. The `apply` method returns True to cache the response, False to skip. ```python from hishel import BaseFilter, Request, Response class MyResponseFilter(BaseFilter[Response]): def needs_body(self) -> bool: """Return True if the filter needs access to the response body.""" return False def apply(self, item: Response, body: bytes | None) -> bool: """ Return True to cache the response, False to skip caching. Args: item: The response to filter body: The response body (only if needs_body() returns True) """ # Your filtering logic here return True ``` -------------------------------- ### Configure Max Stream Size for Redis Storage (Async) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Limit the maximum size of a response body streamed to Redis using an asynchronous client to prevent excessive memory usage. Set to None to disable the cap. Defaults to 10 MiB. ```python from redis.asyncio import Redis from hishel import AsyncRedisStorage client = Redis(host="localhost", port=6379) storage = AsyncRedisStorage(client=client, max_stream_size=50 * 1024 * 1024) ``` -------------------------------- ### Configure Custom Key Prefix for Redis Storage Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Set a custom prefix for all keys stored in Redis. This is useful for isolating cache data when sharing a Redis instance. ```python from redis import Redis from hishel import RedisStorage client = Redis(host="localhost", port=6379) storage = RedisStorage(client=client, key_prefix="myapp") ``` ```python from redis.asyncio import Redis from hishel import AsyncRedisStorage client = Redis(host="localhost", port=6379) storage = AsyncRedisStorage(client=client, key_prefix="myapp") ``` -------------------------------- ### Check if Response Was Served From Cache (requests) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Use the `X-Hishel-From-Cache` header to check if the response was served from the cache when using the requests library. This helps in debugging cache behavior. ```python import requests from hishel.requests import CacheAdapter session = requests.Session() session.mount("http://", CacheAdapter()) session.mount("https://", CacheAdapter()) response = session.get("https://api.example.com/data") if response.headers.get("X-Hishel-From-Cache") == "true": print("✓ Cache hit") else: print("✗ Cache miss - fetched from origin") ``` -------------------------------- ### Set Default Entry TTL for SQLite Storage Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Define a default Time-To-Live (TTL) for cache entries when a request does not specify its own TTL. This value is in seconds. ```python from hishel import SyncSqliteStorage storage = SyncSqliteStorage(default_ttl=3600) ``` ```python from hishel import AsyncSqliteStorage storage = AsyncSqliteStorage(default_ttl=3600) ``` -------------------------------- ### Create Custom Request Filter Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Define a custom filter for requests by inheriting from BaseFilter[Request]. Implement `needs_body` to indicate if the request body is required and `apply` for filtering logic. The `apply` method returns True to allow caching, False to bypass. ```python from hishel import BaseFilter, Request, Response class MyRequestFilter(BaseFilter[Request]): def needs_body(self) -> bool: """Return True if the filter needs access to the request body.""" return False def apply(self, item: Request, body: bytes | None) -> bool: """ Return True to allow caching, False to bypass cache. Args: item: The request to filter body: The request body (only if needs_body() returns True) """ # Your filtering logic here return True ``` -------------------------------- ### Configure SpecificationPolicy for Shared Cache Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Set the 'shared' option in CacheOptions to True for a shared cache (proxy/CDN) or False for a private cache (browser). ```python # Shared cache (proxy/CDN) policy = SpecificationPolicy( cache_options=CacheOptions(shared=True) ) ``` ```python # Private cache (browser) policy = SpecificationPolicy( cache_options=CacheOptions(shared=False) ) ``` -------------------------------- ### FastAPI Cache-Control Headers Only Source: https://github.com/karpetrosyan/hishel/blob/master/docs/fastapi.md Use the `cache()` dependency to add Cache-Control headers to FastAPI routes. This controls caching behavior for clients like browsers and CDNs. ```python from fastapi import FastAPI from hishel.fastapi import cache app = FastAPI() @app.get("/api/data", dependencies=[cache(max_age=300, public=True)]) async def get_data(): # Cache-Control: public, max-age=300 return {"data": "Clients will cache this for 5 minutes"} ``` -------------------------------- ### Include Request Body in Cache Key with requests Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Set the `X-Hishel-Body-Key` header to `"true"` to include the request body in cache key generation. This is useful for POST requests or GraphQL queries with varying bodies. ```python import requests from hishel.requests import CacheAdapter session = requests.Session() session.mount("http://", CacheAdapter()) session.mount("https://", CacheAdapter()) response = session.post( "https://api.example.com/search", json={"query": "python"}, headers={"X-Hishel-Body-Key": "true"} ) ``` -------------------------------- ### Use SpecificationPolicy with ASGICacheMiddleware Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Integrate SpecificationPolicy with ASGICacheMiddleware to cache responses for ASGI applications. This configuration uses a shared server-side cache. ```python from hishel.asgi import ASGICacheMiddleware from hishel import SpecificationPolicy, CacheOptions policy = SpecificationPolicy( cache_options=CacheOptions( shared=True, # Server-side shared cache allow_stale=False, ) ) app = ASGICacheMiddleware( app=your_asgi_app, policy=policy, ) ``` -------------------------------- ### Use SpecificationPolicy with SyncCacheClient Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Employ SpecificationPolicy with SyncCacheClient for synchronous HTTP requests, configuring it as a shared cache that allows stale responses. ```python import httpx from hishel import SyncCacheClient, SpecificationPolicy, CacheOptions from hishel import CacheOptions policy = SpecificationPolicy( cache_options=CacheOptions( shared=True, # Shared proxy cache allow_stale=True, ) ) with SyncCacheClient(policy=policy) as client: response = client.get("https://api.example.com/data") ``` -------------------------------- ### Set TTL for Cached Response using requests Headers Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md For requests, set the `X-Hishel-Ttl` header to specify a custom time-to-live for a cached response in seconds. Ensure the CacheAdapter is mounted to the session. ```python import requests from hishel.requests import CacheAdapter session = requests.Session() session.mount("http://", CacheAdapter()) session.mount("https://", CacheAdapter()) response = session.get( "https://api.example.com/data", headers={"X-Hishel-Ttl": "3600"} ) ``` -------------------------------- ### Configure SpecificationPolicy Allow Stale Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Control serving of stale responses with 'allow_stale' in CacheOptions. Set to False for conservative caching, True to allow stale responses when directives permit. ```python # Conservative: never serve stale policy = SpecificationPolicy( cache_options=CacheOptions(allow_stale=False) ) ``` ```python # Permissive: serve stale when allowed by directives policy = SpecificationPolicy( cache_options=CacheOptions(allow_stale=True) ) ``` -------------------------------- ### Update Project Version Source: https://github.com/karpetrosyan/hishel/blob/master/docs/contributing.md Modify the version number in the `pyproject.toml` file for a new release. ```toml [project] version = "1.1.6" # Update to new version ``` -------------------------------- ### Check if Response Was Stored in Cache (httpx) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Use `response.extensions.get('hishel_stored')` to verify if the response was successfully stored in the cache. This helps in debugging why responses might not be cached. ```python from hishel.httpx import SyncCacheClient client = SyncCacheClient() response = client.get("https://api.example.com/data") if response.extensions.get("hishel_stored"): print("✓ Response stored in cache") else: print("✗ Response not cached") ``` -------------------------------- ### Commit Version Changes Source: https://github.com/karpetrosyan/hishel/blob/master/docs/contributing.md Commit the updated `pyproject.toml` and `CHANGELOG.md` files with an unconventional commit message. ```bash git add pyproject.toml CHANGELOG.md git commit -m "Version 1.1.6" ``` -------------------------------- ### Use SpecificationPolicy with AsyncCacheClient Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Integrate SpecificationPolicy with AsyncCacheClient for asynchronous HTTP requests, configuring it as a private cache that does not serve stale responses. ```python import httpx from hishel import AsyncCacheClient, SpecificationPolicy, CacheOptions policy = SpecificationPolicy( cache_options=CacheOptions( shared=False, # Private browser cache allow_stale=False, ) ) async with AsyncCacheClient(policy=policy) as client: response = await client.get("https://api.example.com/data") ``` -------------------------------- ### Include Request Body in Cache Key with httpx Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Set `hishel_body_key` to `True` via extensions to include the request body in cache key generation. This is useful for POST requests or GraphQL queries with varying bodies. ```python from hishel.httpx import SyncCacheClient client = SyncCacheClient() response = client.post( "https://api.example.com/search", json={"query": "python"}, extensions={"hishel_body_key": True} ) ``` -------------------------------- ### Set TTL for Cached Response using httpx Headers Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Alternatively, set the `X-Hishel-Ttl` header to specify a custom time-to-live for a cached response in seconds. This method is compatible with httpx. ```python from hishel.httpx import SyncCacheClient client = SyncCacheClient() response = client.get( "https://api.example.com/data", headers={"X-Hishel-Ttl": "3600"} ) ``` -------------------------------- ### Set TTL for Cached Response using httpx Extensions Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Use the `hishel_ttl` extension to set a custom time-to-live for a cached response in seconds. This overrides the storage's default TTL. ```python from hishel.httpx import SyncCacheClient client = SyncCacheClient() response = client.get( "https://api.example.com/data", extensions={"hishel_ttl": 3600} ) ``` -------------------------------- ### Enable Refresh TTL on Access for SQLite Storage Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Configure the storage to refresh the TTL of a cache entry each time it is accessed. This keeps frequently used items in the cache longer. ```python from hishel import SyncSqliteStorage storage = SyncSqliteStorage(refresh_ttl_on_access=True) ``` ```python from hishel import AsyncSqliteStorage storage = AsyncSqliteStorage(refresh_ttl_on_access=True) ``` -------------------------------- ### Set Default Entry TTL for Redis Storage Source: https://github.com/karpetrosyan/hishel/blob/master/docs/storages.md Define a default TTL for cache entries in Redis when a request does not specify its own TTL. This value is in seconds. ```python from redis import Redis from hishel import RedisStorage client = Redis(host="localhost", port=6379) storage = RedisStorage(client=client, ttl=3600) ``` ```python from redis.asyncio import Redis from hishel import AsyncRedisStorage client = Redis(host="localhost", port=6379) storage = AsyncRedisStorage(client=client, ttl=3600) ``` -------------------------------- ### Cache Public API Data in FastAPI Source: https://github.com/karpetrosyan/hishel/blob/master/docs/fastapi.md Cache responses for public API endpoints for a specified duration using `max_age` and `public=True`. ```python @app.get("/api/articles", dependencies=[cache(max_age=300, public=True)]) async def get_articles(): return {"articles": [...]} ``` -------------------------------- ### Filter by URL Pattern Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Implement a request filter to cache only requests matching a specific URL pattern using regular expressions. This filter requires the `re` module and `BaseFilter` from `hishel`. ```python import re from hishel import BaseFilter, FilterPolicy, Request class URLPatternFilter(BaseFilter[Request]): def __init__(self, pattern: str): self.pattern = re.compile(pattern) def needs_body(self) -> bool: return False def apply(self, item: Request, body: bytes | None) -> bool: # Only cache requests matching the pattern return bool(self.pattern.search(str(item.url))) ``` ```python # Cache only API endpoints policy = FilterPolicy( request_filters=[ URLPatternFilter(r'/api/.*') ] ) ``` -------------------------------- ### Filter by Content Type Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Implement a response filter to cache responses based on their content type. It checks if any of the allowed content type strings are present in the response's 'content-type' header. ```python from hishel import BaseFilter, FilterPolicy, Response class ContentTypeFilter(BaseFilter[Response]): def __init__(self, allowed_types: list[str]): self.allowed_types = allowed_types def needs_body(self) -> bool: return False def apply(self, item: Response, body: bytes | None) -> bool: content_type = item.headers.get("content-type", "") return any(allowed in content_type for allowed in self.allowed_types) ``` ```python # Cache only JSON and XML responses policy = FilterPolicy( response_filters=[ ContentTypeFilter(["application/json", "application/xml"]) ] ) ``` -------------------------------- ### Check if Response Was Stored in Cache (requests) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Check the `X-Hishel-Stored` header to confirm if the response was successfully stored in the cache when using the requests library. This is useful for verifying cache storage success rates. ```python import requests from hishel.requests import CacheAdapter session = requests.Session() session.mount("http://", CacheAdapter()) session.mount("https://", CacheAdapter()) response = session.get("https://api.example.com/data") if response.headers.get("X-Hishel-Stored") == "true": print("✓ Response stored in cache") else: print("✗ Response not cached") ``` -------------------------------- ### Filter with Body Inspection Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Create a response filter that inspects the response body. This filter requires `needs_body()` to return True. It parses the body as JSON and caches only if a 'cacheable' field is present and set to True. Handles JSON decoding errors. ```python import json from hishel import BaseFilter, FilterPolicy, Response class JSONResponseFilter(BaseFilter[Response]): def needs_body(self) -> bool: # We need access to the body to inspect it return True def apply(self, item: Response, body: bytes | None) -> bool: if body is None: return False try: data = json.loads(body) # Cache only if response contains 'cacheable' field set to True return data.get("cacheable", False) except json.JSONDecodeError: return False ``` ```python policy = FilterPolicy( response_filters=[JSONResponseFilter()] ) ``` -------------------------------- ### Filter by Response Status Code Source: https://github.com/karpetrosyan/hishel/blob/master/docs/policies.md Create a response filter to cache only responses with specific status codes. This filter takes a list of allowed integer status codes and checks against the response's `status_code` attribute. ```python from hishel import BaseFilter, FilterPolicy, Response class StatusCodeFilter(BaseFilter[Response]): def __init__(self, allowed_codes: list[int]): self.allowed_codes = allowed_codes def needs_body(self) -> bool: return False def apply(self, item: Response, body: bytes | None) -> bool: # Only cache successful responses return item.status_code in self.allowed_codes ``` ```python # Cache only 200 and 304 responses policy = FilterPolicy( response_filters=[ StatusCodeFilter([200, 304]) ] ) ``` -------------------------------- ### Check if Response Was Revalidated (requests) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Check the `X-Hishel-Revalidated` header to see if a stale cached response was revalidated with the origin server when using the requests library. This aids in debugging cache freshness logic. ```python import requests from hishel.requests import CacheAdapter session = requests.Session() session.mount("http://", CacheAdapter()) session.mount("https://", CacheAdapter()) response = session.get("https://api.example.com/data") if response.headers.get("X-Hishel-Revalidated") == "true": print("Response was revalidated (304 Not Modified)") ``` -------------------------------- ### Cache Private User Data in FastAPI Source: https://github.com/karpetrosyan/hishel/blob/master/docs/fastapi.md Cache user-specific data only in the browser's cache by setting `private=True`. This prevents caching by shared caches like CDNs. ```python @app.get("/api/user/profile", dependencies=[cache(max_age=300, private=True)]) async def get_profile(): return {"user": "john_doe"} ``` -------------------------------- ### Check if Response Was Revalidated (httpx) Source: https://github.com/karpetrosyan/hishel/blob/master/docs/metadata.md Use `response.extensions.get('hishel_revalidated')` to check if a stale cached response was revalidated with the origin server. This is useful for tracking conditional request behavior. ```python from hishel.httpx import SyncCacheClient client = SyncCacheClient() response = client.get("https://api.example.com/data") if response.extensions.get("hishel_revalidated"): print("Response was revalidated (304 Not Modified)") ``` -------------------------------- ### Disable Caching in FastAPI Source: https://github.com/karpetrosyan/hishel/blob/master/docs/fastapi.md Prevent caching of sensitive data by setting `no_store=True` in the `cache()` dependency. This ensures the response is never stored by any cache. ```python @app.get("/api/secrets", dependencies=[cache(no_store=True)]) async def get_secrets(): return {"secret": "value"} ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.