api: restructure exception generation to be more ergonomic in the code
This commit is contained in:
parent
60c4770280
commit
2f991a6b02
5 changed files with 153 additions and 81 deletions
|
|
@ -1,8 +1,11 @@
|
|||
from typing import Mapping, Optional
|
||||
from typing import Mapping, Optional, Self
|
||||
from fastapi import HTTPException, Request, Response
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.utils import is_body_allowed_for_status_code
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from fastapi import status
|
||||
from pydantic import HttpUrl
|
||||
from starlette.datastructures import URL
|
||||
|
||||
from dooris_api import models
|
||||
|
||||
|
|
@ -11,16 +14,60 @@ class HttpProblemException(HTTPException):
|
|||
problem: models.HttpProblemDetail
|
||||
headers: Optional[Mapping[str, str]]
|
||||
|
||||
def __init__(self, problem: models.HttpProblemDetail, headers: Optional[Mapping[str, str]] = None):
|
||||
def __init__(
|
||||
self,
|
||||
problem: models.HttpProblemDetail,
|
||||
headers: Optional[Mapping[str, str]] = None,
|
||||
):
|
||||
self.problem = problem
|
||||
super().__init__(status_code=problem.status, headers=headers)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.problem)
|
||||
|
||||
@classmethod
|
||||
def unauthorized(cls, request_uri: str | URL) -> Self:
|
||||
return cls(
|
||||
problem=models.HttpProblemDetail(
|
||||
type=models.HttpProblemType.UNAUTHORIZED,
|
||||
status=status.HTTP_401_UNAUTHORIZED,
|
||||
title="Unauthorized",
|
||||
detail="You tried to access a ressource which requires authentication but you are not authenticated",
|
||||
instance=HttpUrl(str(request_uri)),
|
||||
)
|
||||
)
|
||||
|
||||
async def problem_exception_handler(request: Request, exc: HttpProblemException) -> Response:
|
||||
@classmethod
|
||||
def lock_not_found(cls, requested_lock: str, request_uri: str | URL) -> Self:
|
||||
return cls(
|
||||
problem=models.HttpProblemDetail(
|
||||
type=models.HttpProblemType.LOCK_NOT_FOUND,
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
title="Lock not found",
|
||||
detail=f"You tried to interact with lock {requested_lock!r} that is not known to dooris",
|
||||
instance=str(request_uri),
|
||||
)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def forbidden_to_operate(cls, request_uri: str | URL) -> Self:
|
||||
return cls(
|
||||
problem=models.HttpProblemDetail(
|
||||
type=models.HttpProblemType.FORBIDDEN_TO_OPERATE,
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
title="Forbidden to operate locks",
|
||||
detail="You are not allowed to operate locks",
|
||||
instance=str(request_uri),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def problem_exception_handler(
|
||||
request: Request, exc: HttpProblemException
|
||||
) -> Response:
|
||||
headers = exc.headers
|
||||
if not is_body_allowed_for_status_code(exc.problem.status):
|
||||
return Response(status_code=exc.status_code, headers=headers)
|
||||
return JSONResponse(jsonable_encoder(exc.problem), status_code=exc.status_code, headers=exc.headers)
|
||||
return JSONResponse(
|
||||
jsonable_encoder(exc.problem), status_code=exc.status_code, headers=exc.headers
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue