'Modern apis with FastAPI - Redis Caching

I'm trying to implement the redis caching in my API for the first time it is a simple fastapi application which is using openweather api to query some weather information and my intention is to cache each json response in the redis server. I'hve made it to work with single key city but with this approach validating query parameters not working with the error handling I put in the place.

caching.py

import sys
from datetime import timedelta
import json

import redis

from services.openweather_service import get_report


def redis_connect() -> redis.client.Redis:
    try:
        client = redis.Redis(
            host="localhost",
            port=6379,
            db=0,
        )
        ping = client.ping()
        if ping is True:
            return client
    except redis.ConnectionError:
        print("Connection Error!")
        sys.exit(1)


client = redis_connect()


def get_routes_from_cache(key: str) -> str:
    """Data from redis."""

    val = client.get(key)
    return val


def set_routes_to_cache(key: str, value: str) -> bool:
    """Data to redis."""

    state = client.setex(
        key,
        timedelta(hours=24),
        value=value,
    )
    return state


async def route_optima(city: str, state: str, country: str, units=None) -> dict:

    location = {"city": city, "state": state, "country": country, "units": units}

    # First it looks for the data in redis cache
    data = get_routes_from_cache(key=json.dumps(location))
    # print(data)
    # print(type(data))

    # If cache is found then serves the data from cache
    if data is not None:
        data = data.decode("UTF-8")
        data_dict = json.loads(data)
        print(data_dict)
        print(type(data_dict))
        data["cache"] = True
        return data

    else:
        # If cache is not found then sends request to the OpenWeather API
        data = await get_report(city, state, country, units)

        # This block sets saves the respose to redis and serves it directly
        data["cache"] = False
        data = json.dumps(data)
        state = set_routes_to_cache(key=json.dumps(location), value=json.dumps(data))

        if state is True:
            return json.dumps(data)
        return data

Then I took a different approach by making the query params location = {"city": city, "state": state, "country": country, "units": units} as a key and the json response as a value but when app try to get the response from the cache here it got weird like right after passing the query params dict into the json.dumps it gives me the bytes object and so I decode it with decode("utf-8") but instead of coming back as a dict it gives me <class 'str'> type object. There I am lost... can anyone help me out here?

weather_api.py

from typing import Optional
import fastapi
from fastapi import Depends

from models.location import Location
from infrastructure.caching import route_optima
from models.validation_error import ValidationError

router = fastapi.APIRouter()


@router.get("/api/weather/{city}")
async def weather(loc: Location = Depends(), units: Optional[str] = "metric"):
    return await route_optima(loc.city, loc.state, loc.country, units)

And if I am using the wrong approach here then please point to the best approach to take here.



Solution 1:[1]

As you are using Fastapi, it is better to use aioredis to leverage the async functionality.

Solution 2:[2]

It turns out I was returning the wrong data it should be like this

# If cache is found then serves the data from cache
    if data is not None:
        data = data.decode("UTF-8")
        data_dict = json.loads(data)
        print(data_dict)
        print(type(data_dict))
        data_dict["cache"] = True
        return data_dict

and everything works fine.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Raisul
Solution 2 X-somtheing