""" Caching middleware for the OpenEventDatabase. """ from oedb.utils.logging import logger class CacheMiddleware: """ Middleware that adds caching headers to responses. This middleware adds appropriate Cache-Control headers to responses based on the endpoint and request method. It helps reduce server load by allowing clients to cache responses for a specified period. """ def __init__(self, default_max_age=60): """ Initialize the middleware with default caching settings. Args: default_max_age: Default max-age in seconds for cacheable responses. """ self.default_max_age = default_max_age # Define caching rules for different endpoints # Format: (endpoint_prefix, method, max_age) self.caching_rules = [ # Cache GET requests to /event for 60 seconds ('/event', 'GET', 60), # Cache GET requests to /stats for 300 seconds (5 minutes) ('/stats', 'GET', 300), # Cache GET requests to /demo for 3600 seconds (1 hour) ('/demo', 'GET', 3600), # Don't cache search results ('/event/search', 'POST', 0), ] def process_response(self, req, resp, resource, params): """ Add caching headers to the response. Args: req: The request object. resp: The response object. resource: The resource object. params: The request parameters. """ # Don't add caching headers for error responses if resp.status_code >= 400: self._add_no_cache_headers(resp) return # Check if the request matches any caching rules max_age = self._get_max_age(req) if max_age > 0: # Add caching headers logger.debug(f"Adding caching headers with max-age={max_age} to {req.method} {req.path}") resp.set_header('Cache-Control', f'public, max-age={max_age}') resp.set_header('Vary', 'Accept-Encoding') else: # Add no-cache headers self._add_no_cache_headers(resp) def _get_max_age(self, req): """ Determine the max-age value for the current request. Args: req: The request object. Returns: int: The max-age value in seconds, or 0 for no caching. """ # Check if the request matches any caching rules for endpoint, method, max_age in self.caching_rules: if req.path.startswith(endpoint) and req.method == method: return max_age # Default: no caching for write operations, default max-age for read operations if req.method in ('POST', 'PUT', 'DELETE', 'PATCH'): return 0 elif req.method == 'GET': return self.default_max_age else: return 0 def _add_no_cache_headers(self, resp): """ Add headers to prevent caching. Args: resp: The response object. """ logger.debug("Adding no-cache headers to response") resp.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') resp.set_header('Pragma', 'no-cache') resp.set_header('Expires', '0')