# FastAPI-Cacher
An intuitive caching library for FastAPI inspired by Flask-Caching.
It uses decorators for easy endpoint caching, supports both **absolute** and **sliding window expiration** mechanisms.
## Installation
Install and update using pip
```bash
pip install -U fastapi-cacher
```
## Cache Types
Configured in the CacheConfig class:
```python
# Options: "SimpleCache", "RedisCache", "MongoCache", "MemCache"
cache_type = "SimpleCache" # Default: "SimpleCache",
```
#### `SimpleCache`
- Suitable for development and single-thread applications.
- Default cache type if cache_type is not specified or CacheConfig is not provided.
#### `RedisCache`
- Robust option for production environments.
- Supports distributed caching.
- Configuration requires specifying either `redis_url` or both `redis_host` and `redis_password`.
#### `MongoCache`
- Uses MongoDB's `expireAfterSeconds` index to automatically manage the expiration of cached entries.
- Requires a MongoDB connection URL.
#### `MemCache`
- Uses a Memcached server to store cached data.
- Specify `memcache_host` and `memcache_port`.
### Each cache type has specific attributes in the `CacheConfig` that need to be configured:
```python
from fastapi_cacher import CacheConfig
# For SimpleCache
cache_config = CacheConfig(
cache_type="SimpleCache",
simple_cache_threshold=100, # Default: 100 (number of items to store in cache, before deleting the oldest)
)
# For RedisCache
cache_config = CacheConfig(
cache_type="RedisCache",
redis_url="redis://localhost:6379", # either redis_url or redis_host, redis_port, redis_password
redis_host="your_redis_host",
redis_port=6379, # Default: 6379
redis_password="your_redis_password",
redis_db=0, # Default: 0
)
# For MongoCache
cache_config = CacheConfig(
cache_type="MongoCache",
mongo_url="mongodb://user:password@localhost:27017",
mongo_database="fastapi_cache",
mongo_collection="your_cache_collection", # Default: "cache"
mongo_direct_connection=False # Default: False
)
# For MemCache
cache_config = CacheConfig(
cache_type="MemCache",
memcache_host="your_memcache_host", # Default: ""
memcache_port=11211, # Default: 11211
memcache_threshold=100 # Default: 100 (number of items to store in cache, before deleting the oldest)
)
```
## Generic CacheConfig Attributes with Defaults:
- `cache_type` (str) = `SimpleCache`: Sets the caching strategy (e.g., SimpleCache, RedisCache).
- `default_timeout` (int) = `300`: Default timeout in seconds if not specified in decorator.
- `app_space` (str) = `fastapi-cacher`: Namespace prefix for cache keys to avoid conflicts.
- `coder` (Coder) = `JsonCoder`: Serialization coder for caching.
- `sliding_expiration` (bool) = `False`: Sets the caching mechanism globally, if True, the expiration time will be reset
on every access **(overwritten by the decorator if specified there)**.
- Time Constants (`ONE_HOUR`, `ONE_DAY`, etc.): Predefined time intervals in seconds for easy setup of expiration times.
### Example:
```python
cache_config = CacheConfig(
cache_type="SimpleCache",
default_timeout=600,
app_space="my_app",
sliding_expiration=True
)
```
## Usage
To use the caching functionality, decorate your FastAPI endpoints with the @cache.cached decorator.
Here are some examples for each type of cache:
```python
from asyncio import sleep
from fastapi import FastAPI, Request, Response
from fastapi_cacher import Cache, CacheConfig
app = FastAPI()
# Configuring with RedisCache; for settings of other cache types, see the CacheConfig section above.
cache_config = CacheConfig(
cache_type="RedisCache",
redis_host="your_redis_host",
redis_password="your_redis_password",
default_timeout=600, # default if not specified in the decorator
app_space="fastapi-cacher",
sliding_expiration=False
)
cache = Cache(config=cache_config)
@app.get("/item/{item_id}")
@cache.cached(timeout=300,
sliding_expiration=False,
namespace="item_detail",
query_params=True,
json_body=False,
require_auth_header=False)
async def get_item(request: Request, response: Response, item_id: int):
"""
request parameter is required in the function signature for the cache to work.
request and response parameters can be named differently:
async def get_item(req: Request, resp: Response, item_id: int):
"""
await sleep(3)
return {"id": item_id, "name": "Item Name"}
@app.get("/items/")
@cache.cached(timeout=cache_config.ONE_HOUR,
namespace="item_detail")
async def get_items(request: Request, response: Response):
"""
request parameter is required in the function signature for the cache to work.
request and response parameters can be named differently:
async def get_item(req: Request, resp: Response, item_id: int):
"""
await sleep(3)
return {"id": 1, "name": "Item Name"}
```
### `cache.cached` decorator arguments with defaults:
- `timeout` (int) = `None`: Timeout in seconds. Set to `0` to never expire. If not specified, the default timeout
from the cache config is used. A pre-calculated values in the cache_config can be used, e.g.,
`cache_config.ONE_HOUR`, `cache_config.ONE_DAY`, etc.
- `sliding_expiration` (bool) = `None`: If True, the expiration time will be reset on every access. If set, it
overwrites the cache_config setting.
- `namespace` (str) = `""`: Allows scoping of cache keys.
- `query_params` (book) = `True`: Consider URL query parameters for caching.
- `json_body` = `False`: Include requests JSON body in the cache string key.
- `require_auth_header` = `False`: Include the Authorization header in the cache string key.
If set to True, the Authorization header is required in the request and if not present - Raises `HTTPException(401)`.
## More about the sliding expiration mechanism:
The sliding expiration mechanism resets the expiration time of a cached item each time it is accessed. This means the
item will only be deleted if it is not accessed for the specified timeout period.
- Global Setting: Set in `CacheConfig` to apply by default to all endpoints.
- Individual Setting: Can be overridden in the `cache.cached` decorator for specific endpoints.
### Clearing the Cache
#### Endpoints can be configured to clear the cache selectively or entirely.
```python
@app.post('/clear-cache/')
async def clear_cache(namespace: str = None, key: str = None):
"""
Clears the cache.
- `namespace`: Optional. The namespace of the cache to clear.
- `key`: Optional. The specific key within the namespace to clear.
If no parameters are provided, the entire cache will be cleared.
example:
http://domain/clear-cache/?namespace=test&key=specific-key
"""
await cache.clear(namespace=namespace, key=key)
return "Cache cleared!"
```
### Other `cache` methods:
```python
# set
await cache.set(key="key", value="value", timeout=300)
# get
value = await cache.get(key="key")
# get with ttl
ttl, cached_result = await cache.get_with_ttl(key="key")
```
## Contributions
Contributions to the fastapi-cacher project are welcome. Please ensure to follow best practices for code quality and add
tests for new features.
## License
This project is licensed under the MIT License.
# Changelog
## [0.3.0] - 2024-07-10:
### Added
- Support for sliding window expiration mechanism.
## [0.2.0] - 2024-07-08:
### Added
- Support for MongoDB cache: `MongoCache`.
- Support for Authorization header in `cache.cached` decorator.
- Support for JSON body in `cache.cached` decorator.
- Support for dynamic `Request` and `Response` parameters names in the function signature.
### Fixed
- Issue with json parsing of MemCache results.
### Changed
- `default_timeout` in RedisCache from 150 to 300.
- Updated README file with more examples.
## [0.1.0] - 2024-06-24 initial release
### Added
- Initial release of the package.
Raw data
{
"_id": null,
"home_page": "https://github.com/Fahadukr/fastapi-cacher",
"name": "fastapi-cacher",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": null,
"author": "Fahad Mawlood",
"author_email": "fahadukr@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/6c/d5/e7bc348bbc85bdffda3d0022c838e910c6eef000696cad99320be920b658/fastapi-cacher-0.3.1.tar.gz",
"platform": null,
"description": "# FastAPI-Cacher\r\n\r\nAn intuitive caching library for FastAPI inspired by Flask-Caching.\r\nIt uses decorators for easy endpoint caching, supports both **absolute** and **sliding window expiration** mechanisms.\r\n\r\n## Installation\r\n\r\nInstall and update using pip\r\n\r\n```bash\r\npip install -U fastapi-cacher\r\n```\r\n\r\n## Cache Types\r\n\r\nConfigured in the CacheConfig class:\r\n\r\n```python\r\n# Options: \"SimpleCache\", \"RedisCache\", \"MongoCache\", \"MemCache\"\r\ncache_type = \"SimpleCache\" # Default: \"SimpleCache\", \r\n```\r\n\r\n#### `SimpleCache`\r\n\r\n- Suitable for development and single-thread applications.\r\n- Default cache type if cache_type is not specified or CacheConfig is not provided.\r\n\r\n#### `RedisCache`\r\n\r\n- Robust option for production environments.\r\n- Supports distributed caching.\r\n- Configuration requires specifying either `redis_url` or both `redis_host` and `redis_password`.\r\n\r\n#### `MongoCache`\r\n\r\n- Uses MongoDB's `expireAfterSeconds` index to automatically manage the expiration of cached entries.\r\n- Requires a MongoDB connection URL.\r\n\r\n#### `MemCache`\r\n\r\n- Uses a Memcached server to store cached data.\r\n- Specify `memcache_host` and `memcache_port`.\r\n\r\n### Each cache type has specific attributes in the `CacheConfig` that need to be configured:\r\n\r\n```python\r\nfrom fastapi_cacher import CacheConfig\r\n\r\n# For SimpleCache\r\ncache_config = CacheConfig(\r\n cache_type=\"SimpleCache\",\r\n simple_cache_threshold=100, # Default: 100 (number of items to store in cache, before deleting the oldest)\r\n)\r\n\r\n# For RedisCache\r\ncache_config = CacheConfig(\r\n cache_type=\"RedisCache\",\r\n redis_url=\"redis://localhost:6379\", # either redis_url or redis_host, redis_port, redis_password\r\n redis_host=\"your_redis_host\",\r\n redis_port=6379, # Default: 6379\r\n redis_password=\"your_redis_password\",\r\n redis_db=0, # Default: 0\r\n)\r\n\r\n# For MongoCache\r\ncache_config = CacheConfig(\r\n cache_type=\"MongoCache\",\r\n mongo_url=\"mongodb://user:password@localhost:27017\",\r\n mongo_database=\"fastapi_cache\",\r\n mongo_collection=\"your_cache_collection\", # Default: \"cache\"\r\n mongo_direct_connection=False # Default: False\r\n)\r\n\r\n# For MemCache\r\ncache_config = CacheConfig(\r\n cache_type=\"MemCache\",\r\n memcache_host=\"your_memcache_host\", # Default: \"\"\r\n memcache_port=11211, # Default: 11211\r\n memcache_threshold=100 # Default: 100 (number of items to store in cache, before deleting the oldest)\r\n)\r\n```\r\n\r\n## Generic CacheConfig Attributes with Defaults:\r\n\r\n- `cache_type` (str) = `SimpleCache`: Sets the caching strategy (e.g., SimpleCache, RedisCache).\r\n- `default_timeout` (int) = `300`: Default timeout in seconds if not specified in decorator.\r\n- `app_space` (str) = `fastapi-cacher`: Namespace prefix for cache keys to avoid conflicts.\r\n- `coder` (Coder) = `JsonCoder`: Serialization coder for caching.\r\n- `sliding_expiration` (bool) = `False`: Sets the caching mechanism globally, if True, the expiration time will be reset\r\n on every access **(overwritten by the decorator if specified there)**.\r\n- Time Constants (`ONE_HOUR`, `ONE_DAY`, etc.): Predefined time intervals in seconds for easy setup of expiration times.\r\n\r\n### Example:\r\n\r\n```python\r\ncache_config = CacheConfig(\r\n cache_type=\"SimpleCache\",\r\n default_timeout=600,\r\n app_space=\"my_app\",\r\n sliding_expiration=True\r\n)\r\n```\r\n\r\n## Usage\r\n\r\nTo use the caching functionality, decorate your FastAPI endpoints with the @cache.cached decorator.\r\nHere are some examples for each type of cache:\r\n\r\n```python\r\nfrom asyncio import sleep\r\n\r\nfrom fastapi import FastAPI, Request, Response\r\nfrom fastapi_cacher import Cache, CacheConfig\r\n\r\napp = FastAPI()\r\n# Configuring with RedisCache; for settings of other cache types, see the CacheConfig section above.\r\ncache_config = CacheConfig(\r\n cache_type=\"RedisCache\",\r\n redis_host=\"your_redis_host\",\r\n redis_password=\"your_redis_password\",\r\n default_timeout=600, # default if not specified in the decorator\r\n app_space=\"fastapi-cacher\",\r\n sliding_expiration=False\r\n)\r\ncache = Cache(config=cache_config)\r\n\r\n\r\n@app.get(\"/item/{item_id}\")\r\n@cache.cached(timeout=300,\r\n sliding_expiration=False,\r\n namespace=\"item_detail\",\r\n query_params=True,\r\n json_body=False,\r\n require_auth_header=False)\r\nasync def get_item(request: Request, response: Response, item_id: int):\r\n \"\"\"\r\n request parameter is required in the function signature for the cache to work.\r\n request and response parameters can be named differently:\r\n async def get_item(req: Request, resp: Response, item_id: int):\r\n \"\"\"\r\n await sleep(3)\r\n return {\"id\": item_id, \"name\": \"Item Name\"}\r\n\r\n\r\n@app.get(\"/items/\")\r\n@cache.cached(timeout=cache_config.ONE_HOUR,\r\n namespace=\"item_detail\")\r\nasync def get_items(request: Request, response: Response):\r\n \"\"\"\r\n request parameter is required in the function signature for the cache to work.\r\n request and response parameters can be named differently:\r\n async def get_item(req: Request, resp: Response, item_id: int):\r\n \"\"\"\r\n await sleep(3)\r\n return {\"id\": 1, \"name\": \"Item Name\"}\r\n```\r\n\r\n### `cache.cached` decorator arguments with defaults:\r\n\r\n- `timeout` (int) = `None`: Timeout in seconds. Set to `0` to never expire. If not specified, the default timeout\r\n from the cache config is used. A pre-calculated values in the cache_config can be used, e.g.,\r\n `cache_config.ONE_HOUR`, `cache_config.ONE_DAY`, etc.\r\n- `sliding_expiration` (bool) = `None`: If True, the expiration time will be reset on every access. If set, it\r\n overwrites the cache_config setting.\r\n- `namespace` (str) = `\"\"`: Allows scoping of cache keys.\r\n- `query_params` (book) = `True`: Consider URL query parameters for caching.\r\n- `json_body` = `False`: Include requests JSON body in the cache string key.\r\n- `require_auth_header` = `False`: Include the Authorization header in the cache string key.\r\n If set to True, the Authorization header is required in the request and if not present - Raises `HTTPException(401)`.\r\n\r\n## More about the sliding expiration mechanism:\r\n\r\nThe sliding expiration mechanism resets the expiration time of a cached item each time it is accessed. This means the\r\nitem will only be deleted if it is not accessed for the specified timeout period.\r\n\r\n- Global Setting: Set in `CacheConfig` to apply by default to all endpoints.\r\n- Individual Setting: Can be overridden in the `cache.cached` decorator for specific endpoints.\r\n\r\n### Clearing the Cache\r\n\r\n#### Endpoints can be configured to clear the cache selectively or entirely.\r\n\r\n```python\r\n@app.post('/clear-cache/')\r\nasync def clear_cache(namespace: str = None, key: str = None):\r\n \"\"\"\r\n Clears the cache.\r\n \r\n - `namespace`: Optional. The namespace of the cache to clear.\r\n - `key`: Optional. The specific key within the namespace to clear.\r\n \r\n If no parameters are provided, the entire cache will be cleared.\r\n example:\r\n http://domain/clear-cache/?namespace=test&key=specific-key\r\n \"\"\"\r\n await cache.clear(namespace=namespace, key=key)\r\n return \"Cache cleared!\"\r\n```\r\n\r\n### Other `cache` methods:\r\n\r\n```python\r\n# set \r\nawait cache.set(key=\"key\", value=\"value\", timeout=300)\r\n\r\n# get\r\nvalue = await cache.get(key=\"key\")\r\n\r\n# get with ttl\r\nttl, cached_result = await cache.get_with_ttl(key=\"key\")\r\n```\r\n\r\n## Contributions\r\n\r\nContributions to the fastapi-cacher project are welcome. Please ensure to follow best practices for code quality and add\r\ntests for new features.\r\n\r\n## License\r\n\r\nThis project is licensed under the MIT License.\r\n\r\n\r\n\r\n# Changelog\r\n\r\n## [0.3.0] - 2024-07-10:\r\n\r\n### Added\r\n\r\n- Support for sliding window expiration mechanism.\r\n\r\n## [0.2.0] - 2024-07-08:\r\n\r\n### Added\r\n\r\n- Support for MongoDB cache: `MongoCache`.\r\n- Support for Authorization header in `cache.cached` decorator.\r\n- Support for JSON body in `cache.cached` decorator.\r\n- Support for dynamic `Request` and `Response` parameters names in the function signature.\r\n\r\n### Fixed\r\n\r\n- Issue with json parsing of MemCache results.\r\n\r\n### Changed\r\n\r\n- `default_timeout` in RedisCache from 150 to 300.\r\n- Updated README file with more examples.\r\n\r\n## [0.1.0] - 2024-06-24 initial release\r\n\r\n### Added\r\n\r\n- Initial release of the package.\r\n",
"bugtrack_url": null,
"license": null,
"summary": "A caching library for FastAPI",
"version": "0.3.1",
"project_urls": {
"Homepage": "https://github.com/Fahadukr/fastapi-cacher"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "e71af82c1c401563bacf297ab94b185d26688717177656e206d1abdc63642162",
"md5": "6121c19381c93c89ab1ac6a03db3e4c2",
"sha256": "506dbf88a89fad2007d40cbdb199c143fcecaa6821b1391a2bf56a0fdeb65ed2"
},
"downloads": -1,
"filename": "fastapi_cacher-0.3.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "6121c19381c93c89ab1ac6a03db3e4c2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 26734,
"upload_time": "2024-07-11T18:12:03",
"upload_time_iso_8601": "2024-07-11T18:12:03.330271Z",
"url": "https://files.pythonhosted.org/packages/e7/1a/f82c1c401563bacf297ab94b185d26688717177656e206d1abdc63642162/fastapi_cacher-0.3.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "6cd5e7bc348bbc85bdffda3d0022c838e910c6eef000696cad99320be920b658",
"md5": "f78e40ac1516ce454e4f5b68df406258",
"sha256": "a55744329c4589d247e1e850c448efdd07a6eaf5d455b0c49af9d56424e00e6c"
},
"downloads": -1,
"filename": "fastapi-cacher-0.3.1.tar.gz",
"has_sig": false,
"md5_digest": "f78e40ac1516ce454e4f5b68df406258",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 15488,
"upload_time": "2024-07-11T18:12:07",
"upload_time_iso_8601": "2024-07-11T18:12:07.105237Z",
"url": "https://files.pythonhosted.org/packages/6c/d5/e7bc348bbc85bdffda3d0022c838e910c6eef000696cad99320be920b658/fastapi-cacher-0.3.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-07-11 18:12:07",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Fahadukr",
"github_project": "fastapi-cacher",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "fastapi-cacher"
}