diff --git a/backend/api/schemas/data.py b/backend/api/schemas/data.py deleted file mode 100644 index b8ca9b4..0000000 --- a/backend/api/schemas/data.py +++ /dev/null @@ -1,20 +0,0 @@ -"""Pydantic data models to be reusable anywhere""" - -from pydantic import BaseModel -from enum import Enum - - -class Status(str, Enum): - success = "success" - failed = "failed" - - -class Error(BaseModel): - type: str - code: int - message: str | list[dict] - - -class Success(BaseModel): - code: int | str - message: str diff --git a/backend/api/schemas/errors.py b/backend/api/schemas/errors.py index c9282cb..aa05267 100644 --- a/backend/api/schemas/errors.py +++ b/backend/api/schemas/errors.py @@ -1,25 +1,33 @@ """ Errors used in the API. """ -from api.schemas.data import Error -# NOT_AUTHENTICATED = Error(type="auth", code=10, message="Not authenticated") +# NOT_AUTHENTICATED = Error(err_type="auth", code=10, message="Not authenticated") + +from pydantic import BaseModel + + +class Error(BaseModel): + err_type: str + code: int + message: str | list[dict] + EXPIRED_TOKEN = Error( - type="auth", + err_type="auth", code=105, message="You need to renew the Access token using the refresh token", ) -VALIDATION_ERR = Error(type="validation", code=114, message="") +VALIDATION_ERR = Error(err_type="validation", code=114, message="") -ELIGIBILITY_ERR = Error(type="eligibility", code=115, message="Not eligible") +ELIGIBILITY_ERR = Error(err_type="eligibility", code=115, message="Not eligible") INVALID_ACCESS_TOKEN = Error( - type="token", code=101, message="The Access-Token is not valid" + err_type="token", code=101, message="The Access-Token is not valid" ) INVALID_TOKEN = Error( - type="auth", + err_type="auth", code=103, message="Invalid token", ) diff --git a/backend/api/schemas/response.py b/backend/api/schemas/response.py index 16d2c18..8f4c2fe 100644 --- a/backend/api/schemas/response.py +++ b/backend/api/schemas/response.py @@ -1,62 +1,46 @@ -from typing import Dict, Any +from enum import Enum from pydantic import BaseModel import api.schemas.errors as api_errors -from .data import Status, Error, Success +from typing import Any, Dict +from builtins import Exception as PyException -# ================================== Response Models -class ApiResponse(BaseModel): - """The base ApiResponse model""" +class Status(str, Enum): + success = "success" + failed = "failed" - status: Status = Status.success - success: Success | Dict[str, Any] | BaseModel | None = None - error: Error | None = None - data: Dict[str, Any] | BaseModel | None = None - - def dict(self, *args, **kwargs) -> dict[str, Any]: - kwargs.pop("exclude_none") - return super().dict(*args, exclude_none=True, **kwargs) - - class Config: - use_enum_values = True - - @staticmethod - def schema_extra(schema, model) -> None: - if schema.get("properties")["status"]["default"] == "success": - schema.get("properties").pop("error") - if schema.get("properties")["status"]["default"] == "failed": - schema.get("properties").pop("data") - schema.get("properties").pop("success") +class APIResponse(BaseModel): + status: Status + error: api_errors.Error | None = None + data: Dict[str, Any] | BaseModel | None = None -# ================================== ErrorResponse Models -class ApiException(Exception): - """Exception customized to acts as an ErrorResponse""" +class APIException(PyException): status_code: int - error: Error + error: api_errors.Error - def __init__(self, status_code: int, error: Error): + def __init__(self, status_code: int, error: api_errors.Error): super().__init__(status_code) self.status_code = status_code self.error = error -class INVALID_ACCESS_TOKENResponse(ApiResponse): +class INVALID_ACCESS_TOKENResponse(APIResponse): status: Status = Status.failed - error: Error = api_errors.INVALID_ACCESS_TOKEN + error: api_errors.Error = api_errors.INVALID_ACCESS_TOKEN -class ExpiredTokenResponse(ApiResponse): +class ExpiredTokenResponse(APIResponse): status: Status = Status.failed - error: Error = api_errors.EXPIRED_TOKEN + error: api_errors.Error = api_errors.EXPIRED_TOKEN -class ValidationErrorResponse(ApiResponse): +class ValidationErrorResponse(APIResponse): status: Status = Status.failed - error: Error = api_errors.VALIDATION_ERR + error: api_errors.Error = api_errors.VALIDATION_ERR -class EligibilityErrorResponse(ApiResponse): +class EligibilityErrorResponse(APIResponse): status: Status = Status.failed - error: Error = api_errors.ELIGIBILITY_ERR + error: api_errors.Error = api_errors.ELIGIBILITY_ERR diff --git a/backend/main.py b/backend/main.py index 15f9a49..5541604 100644 --- a/backend/main.py +++ b/backend/main.py @@ -18,8 +18,8 @@ from hypercorn.config import Config from starlette.exceptions import HTTPException as StarletteHTTPException from api.schemas import examples as api_examples -from api.schemas.data import Error, Status -from api.schemas.response import ApiException, ApiResponse +from api.schemas.response import APIException, APIResponse, Status +from api.schemas.errors import Error from utils.response import OurResponse from utils.logger import logger from utils.settings import settings @@ -90,9 +90,9 @@ async def my_exception_handler(_, exception): @app.exception_handler(RequestValidationError) async def validation_exception_handler(_, exc: RequestValidationError): err = jsonable_encoder({"detail": exc.errors()})["detail"] - raise ApiException( + raise APIException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, - error=Error(code=422, type="validation", message=err), + error=Error(code=422, err_type="validation", message=err), ) @@ -113,11 +113,11 @@ async def middle(request: Request, call_next): ): try: response = await call_next(request) - except ApiException as ex: + except APIException as ex: response = JSONResponse( status_code=ex.status_code, content=jsonable_encoder( - ApiResponse(status=Status.failed, error=ex.error) + APIResponse(status=Status.failed, error=ex.error) ), ) stack = [ @@ -157,10 +157,10 @@ async def middle(request: Request, call_next): response = JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, content=jsonable_encoder( - ApiResponse( + APIResponse( status=Status.failed, error=Error( - type="bad request", code=112, message="Invalid request." + err_type="bad request", code=112, message="Invalid request." ), ) ), @@ -249,10 +249,10 @@ async def myoptions(): @app.patch("/{x:path}", include_in_schema=False, dependencies=[Depends(capture_body)]) @app.delete("/{x:path}", include_in_schema=False, dependencies=[Depends(capture_body)]) async def catchall(): - raise ApiException( + raise APIException( status_code=status.HTTP_404_NOT_FOUND, error=Error( - type="catchall", code=501, message="Requested method or path is invalid" + err_type="catchall", code=501, message="Requested method or path is invalid" ), )