""" Response shorthands for FastAPI. """ from functools import wraps from fastapi.responses import JSONResponse from .constants import ResponseAttributes as RespAttr def _protect_data(func): """Protect the 'data' keyword argument from being used in the decorated function. This is to prevent conflicts with the 'data' attribute in the JSON response body, which will only be included if the decorated function is called with the 'data' keyword argument. """ @wraps(func) def wrapper(*args, **kwargs): if RespAttr.DATA in kwargs: raise ValueError( "'data' is a reserved keyword and cannot be used as a key " "in the keyword arguments of this function." ) return func(*args, **kwargs) return wrapper def _json_response(status_code: int, success: bool, **kwargs) -> JSONResponse: """Base JSON response factory.""" return JSONResponse({**kwargs, RespAttr.SUCCESS: success}, status_code) def json_response(status_code: int, data=None, **kwargs) -> JSONResponse: """JSON response factory. Args: status_code (int): Status code. data (dict, optional): Data. Defaults to None. Will only appear in the response body if the status code is in the 200s. **kwargs: Additional keyword arguments which will be included in the response's JSON body. """ @_protect_data def response(**kwargs): if 200 <= status_code < 300: kwargs[RespAttr.DATA] = data return _json_response(status_code, 200 <= status_code < 300, **kwargs) return response(**kwargs) # Usage examples def json_200(**kwargs): """Return a JSON response with status code 200.""" return json_response(200, **kwargs) def json_200_data(data, **kwargs) -> JSONResponse: """Return a JSON response with status code 200 and data.""" return json_response(200, data=data, **kwargs) def json_201(**kwargs) -> JSONResponse: """Return a JSON response with status code 201.""" return json_response(201, **kwargs) def json_201_data(data, **kwargs) -> JSONResponse: """Return a JSON response with status code 201 and data.""" return json_response(201, data=data, **kwargs) def json_400(**kwargs) -> JSONResponse: """Return a JSON response with status code 400.""" return json_response(400, **kwargs) def json_404(**kwargs) -> JSONResponse: """Return a JSON response with status code 404.""" return json_response(404, **kwargs) def json_422(error: str = "Validation Error", **kwargs) -> JSONResponse: """Return a JSON response with status code 422.""" return json_response(422, error=error, **kwargs) def json_500(error: str = "Internal Server Error", **kwargs) -> JSONResponse: """Return a JSON response with status code 500. Args: error (str): Error message to include in the response body. """ return json_response(500, error=error, **kwargs)