Skip to content

Commit

Permalink
Merge pull request #17 from a-luna/patch-release/v0.1.3
Browse files Browse the repository at this point in the history
Patch release/v0.1.3
  • Loading branch information
a-luna authored Apr 24, 2021
2 parents 0a7f1a6 + 84229c5 commit 1745cee
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 15 deletions.
32 changes: 19 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
# `fastapi-redis-cache`
## `fastapi-redis-cache`

[![PyPI version](https://badge.fury.io/py/fastapi-redis-cache.svg)](https://badge.fury.io/py/fastapi-redis-cache) ![PyPI - Downloads](https://img.shields.io/pypi/dm/fastapi-redis-cache?color=%234DC71F) ![PyPI - License](https://img.shields.io/pypi/l/fastapi-redis-cache?color=%25234DC71F) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/fastapi-redis-cache) [![Maintainability](https://api.codeclimate.com/v1/badges/ec0b1d7afb21bd8c23dc/maintainability)](https://codeclimate.com/github/a-luna/fastapi-redis-cache/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/ec0b1d7afb21bd8c23dc/test_coverage)](https://codeclimate.com/github/a-luna/fastapi-redis-cache/test_coverage)
[![PyPI version](https://badge.fury.io/py/fastapi-redis-cache.svg)](https://badge.fury.io/py/fastapi-redis-cache)
![PyPI - Downloads](https://img.shields.io/pypi/dm/fastapi-redis-cache?color=%234DC71F)
![PyPI - License](https://img.shields.io/pypi/l/fastapi-redis-cache?color=%25234DC71F)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/fastapi-redis-cache)
[![Maintainability](https://api.codeclimate.com/v1/badges/ec0b1d7afb21bd8c23dc/maintainability)](https://codeclimate.com/github/a-luna/fastapi-redis-cache/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/ec0b1d7afb21bd8c23dc/test_coverage)](https://codeclimate.com/github/a-luna/fastapi-redis-cache/test_coverage)

### Features

- Cache response data for async and non-async path operation functions.
- Response data is only cached for `GET` operations, applying `@cache` decorator to path functions for other HTTP method types will have no effect.
- Lifetime of cached data is configured separately for each API endpoint.
- Requests with `Cache-Control` header containing `no-cache` or `no-store`are handled correctly (all caching behavior is disabled).
- Requests with `Cache-Control` header containing `no-cache` or `no-store` are handled correctly (all caching behavior is disabled).
- Requests with `If-None-Match` header will receive a response with status `304 NOT MODIFIED` if `ETag` for requested resource matches header value.

## Installation
### Installation

`pip install fastapi-redis-cache`

## Usage
### Usage

### Initialize Redis
#### Initialize Redis

Create a `FastApiRedisCache` instance when your application starts by [defining an event handler for the `"startup"` event](https://fastapi.tiangolo.com/advanced/events/) as shown below:

Expand Down Expand Up @@ -48,9 +54,9 @@ After creating the instance, you must call the `init` method. The only required
- `ignore_arg_types` (`List[Type[object]]`) — Cache keys are created (in part) by combining the name and value of each argument used to invoke a path operation function. If any of the arguments have no effect on the response (such as a `Request` or `Response` object), including their type in this list will ignore those arguments when the key is created. (_Optional_, defaults to `[Request, Response]`)
- The example shown here includes the `sqlalchemy.orm.Session` type, if your project uses SQLAlchemy as a dependency ([as demonstrated in the FastAPI docs](https://fastapi.tiangolo.com/tutorial/sql-databases/)), you should include `Session` in `ignore_arg_types` in order for cache keys to be created correctly ([More info](#cache-keys)).

### `@cache` Decorator
#### `@cache` Decorator

Decorating a path function with `@cache` enables caching for the endpoint. If no arguments are provided, responses will be set to expire after 1 year, which, historically, is the correct way to mark data that "never expires".
Decorating a path function with `@cache` enables caching for the endpoint. **Response data is only cached for `GET` operations**, decorating path functions for other HTTP method types will have no effect. If no arguments are provided, responses will be set to expire after 1 year, which, historically, is the correct way to mark data that "never expires".

```python
# WILL NOT be cached
Expand Down Expand Up @@ -87,7 +93,7 @@ def get_dynamic_data(request: Request, response: Response):
return {"success": True, "message": "this data should only be cached temporarily"}
```

### Response Headers
#### Response Headers

Below is the HTTP response for the `/dynamic_data` endpoint. The `cache-control`, `etag`, `expires`, and `x-fastapi-cache` headers are added because of the `@cache` decorator:

Expand Down Expand Up @@ -117,9 +123,9 @@ If this request was made from a web browser, and a request for the same resource

Similarly, if a request is sent with the `cache-control` header containing `no-cache` or `no-store`, all caching behavior will be disabled and the response will be generated and sent as if endpoint had not been decorated with `@cache`.

### Cache Keys
#### Cache Keys

Consider the `/get_item` API route defined below. This is the first path function we have seen where the response depends on the value of an argument (`user_id: int`). This is a typical CRUD operation where `user_id` is used to retrieve a `User` record from a SQLAlchemy database.
Consider the `/get_user` API route defined below. This is the first path function we have seen where the response depends on the value of an argument (`user_id: int`). This is a typical CRUD operation where `user_id` is used to retrieve a `User` record from a SQLAlchemy database.

```python
@app.get("/get_user", response_model=schemas.User)
Expand Down Expand Up @@ -177,6 +183,6 @@ INFO:fastapi_redis_cache.client: 04/23/2021 07:04:12 PM | KEY_FOUND_IN_CACHE: ke
INFO: 127.0.0.1:50761 - "GET /get_user?user_id=1 HTTP/1.1" 200 OK
```

## Questions/Contributions
### Questions/Contributions

If you have any questions, please open an issue. Any suggestions and contributions are absolutely welcome. This is still a very small and young project, I plan on adding a feature roadmap and further documentation in the near future.
4 changes: 2 additions & 2 deletions src/fastapi_redis_cache/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,10 @@ def serialize_json(json_dict: Dict) -> str:

@staticmethod
def get_etag(cached_data: Union[str, Dict]) -> str:
if isinstance(cached_data, dict):
cached_data = serialize_json(cached_data)
if isinstance(cached_data, bytes):
cached_data = cached_data.decode()
if not isinstance(cached_data, str):
cached_data = serialize_json(cached_data)
return f"W/{hash(cached_data)}"

@staticmethod
Expand Down

0 comments on commit 1745cee

Please sign in to comment.