| from __future__ import annotations |
| from typing import Any, Optional |
|
|
|
|
| class AppError(Exception): |
| status_code: int = 500 |
| code: str = "internal_error" |
|
|
| def __init__(self, message: str, details: Optional[Any] = None) -> None: |
| super().__init__(message) |
| self.details = details |
|
|
| def to_dict(self) -> dict: |
| out: dict = {"error": self.code, "message": str(self)} |
| if self.details is not None: |
| out["details"] = self.details |
| return out |
|
|
|
|
| class NotFoundError(AppError): |
| status_code = 404 |
| code = "not_found" |
|
|
| def __init__(self, resource: str, identifier: Any = None) -> None: |
| msg = f"{resource} not found" |
| if identifier is not None: |
| msg += f": {identifier}" |
| super().__init__(msg) |
|
|
|
|
| class AuthError(AppError): |
| status_code = 401 |
| code = "unauthorized" |
|
|
|
|
| class ForbiddenError(AppError): |
| status_code = 403 |
| code = "forbidden" |
|
|
|
|
| class ValidationError(AppError): |
| status_code = 422 |
| code = "validation_error" |
|
|
| def __init__(self, field: str, message: str) -> None: |
| self.field = field |
| super().__init__(f"{field}: {message}") |
|
|
| def to_dict(self) -> dict: |
| d = super().to_dict() |
| d["field"] = self.field |
| return d |
|
|
|
|
| class ConflictError(AppError): |
| status_code = 409 |
| code = "conflict" |
|
|