fedspendingtransparency/usaspending-api

View on GitHub
usaspending_api/common/cache.py

Summary

Maintainability
A
0 mins
Test Coverage
A
93%
import hashlib
import json

from rest_framework_extensions.key_constructor import bits
from rest_framework_extensions.key_constructor.constructors import DefaultKeyConstructor

from usaspending_api.common.helpers.dict_helpers import order_nested_object


class PathKeyBit(bits.QueryParamsKeyBit):
    """
    Adds query path as a key bit
    """

    def get_source_dict(self, params, view_instance, view_method, request, args, kwargs):
        return {"path": request.path}


class GetPostQueryParamsKeyBit(bits.QueryParamsKeyBit):
    """
    Override QueryParamsKey method in drf-extensions to ensure that the query params part of our cache key includes
    directives in a POST request (i.e., request.data) as well as GET parameters
    """

    def get_source_dict(self, params, view_instance, view_method, request, args, kwargs):

        if hasattr(view_instance, "cache_key_whitelist"):
            whitelist = view_instance.cache_key_whitelist
            params = {}
            for param in whitelist:
                if param in request.query_params:
                    params[param] = request.query_params[param]
                if param in request.data:
                    params[param] = request.data[param]
        else:
            params = dict(request.query_params)
            params.update(dict(request.data))

        if "auditTrail" in params:
            del params["auditTrail"]
        return {"request": json.dumps(order_nested_object(params))}


class USAspendingKeyConstructor(DefaultKeyConstructor):
    """
    Handle cache key construction for API requests. If we never need to create more nuanced keys, see the
    drf-extensions documentation: http://chibisov.github.io/drf-extensions/docs/#default-key-constructor
    """

    path_bit = PathKeyBit()
    request_params = GetPostQueryParamsKeyBit()

    def prepare_key(self, key_dict):
        # Order the key_dict using the order_nested_object function to make sure cache keys are always exactly the same
        ordered_key_dict = json.dumps(order_nested_object(key_dict))
        key_hex = hashlib.md5(ordered_key_dict.encode("utf-8")).hexdigest()
        return key_hex


usaspending_key_func = USAspendingKeyConstructor()