-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Зафиксировать иерархию классов ошибок (#140)
Во время работы над добавлением сваггера для эндпойнтов авторизации (#77) была добавлена определённая иерархия классов ошибок, но так как эта часть не являлась основной целью задачи, то эта иерархия была сделана на скорую руку и содержала определённые недостатки. На данный момент у нас всё ещё нет четкого понимания, как именно мы хотим работать с ошибками, т.к. кажется, что это довольно сложная проблема, в которой необходимо учесть много нюансов. Но несмотря на то, что на данный момент у нас ещё нет конечного варианта архитектуры ошибок, мы всё равно можем поправить хотя бы тот недостаток существующей архитектуры, который виден сейчас. А именно: (Основная проблема из-за которой был инициирован этот рефакторинг) - Объекты ошибок могут иметь разные значения определённых полей, т.к. их определение доступно через конструктор, например: ```python class NotFoundException(HTTPException): """Exception for 404 NOT FOUND error.""" resource: str description = "Requested resource not found." details = "Requested resource doesn't exist or has been deleted." def __init__(self: Self, resource: str, *args: Any, **kwargs: Any) -> None: # pragma: no cover """Initialize object.""" self.resource = resource super().__init__(*args, **kwargs) ``` Это значит, что в разных местах кода, или даже в разных эндпойнтах, могут подниматься ошибки с разным текстом поля `details`: ```python raise NotFoundException(resource="foo", details="foo not found") raise NotFoundException(resource="bar", details="bar not found") ``` И в случае если нам надо будет поменять текст ошибки для ресурса "foo", то необходимо будет использовать полнотекстовый поиск для нахождения в коде всех строк, содержащих `"foo"`. Вместо этого, удобнее было бы иметь конкретный класс ошибки под каждую сущность, без возможности переопределения аттрибутов, например: ```python class FooNotFoundException(NotFoundException): resource = "foo" description = "not found" details = "foo not found" class BarNotFoundException(NotFoundException): resource = "bar" description = "not found" details = "bar not found" ``` таким образом в коде получится: ```python raise FooNotFoundException() raise BarFoundException() ``` Это позволит нам легко изменить текст ошибки для ресурса "foo", просто поменяв значение атрибута в классе. Для решения этой проблемы, необходимо изменить архитектуру классов исключений так, чтобы она удовлетворяла следующим требованиям: 1. Базовые классы исключений находятся в `src/shared/exceptions.py` и определяют интерфейс исключений подклассов, для возможности удобной обработки разных исключений одного типа. Например, если в `src/shared/exceptions.py` определено исключение ```python class NotFoundException(HTTPException): """Exception for 404 NOT FOUND error.""" resource: str description = "Requested resource not found." details = "Requested resource doesn't exist or has been deleted." ``` это значит, что у всех подклассов класса `NotFoundException` должны быть определены поля `resource`, `description` и `details`. (К сожалению, python не предоставляет возможности обеспечить соблюдение этого требования, либо такая возможность не была найдена во время работы над этим тикетом, поэтому разработчикам придётся следить за его соблюдением самостоятельно). Соблюдение этого требования позволит нам обрабатывать все исключения одного и того же типа единообразно, например: ```python @app.exception_handler(NotFoundException) def handle_not_found_exception(request: Request, exception: NotFoundException) -> JSONResponse: # будет работать правильно как для FooNotFoundException так и для BarNotFoundException return JSONResponse( status_code=exception.status_code, content={ "resource": exception.resource, "description": exception.description, "details": exception.details, }, ) ``` 2. Все классы исключений, поднимаемых в коде, находятся в своём "feature-package", например - `FooNotFoundException` и `DuplicateFooException` находятся в `src/foo/exceptions.py` и наследуются от соответствующих им `NotFoundException` и `NotAllowedException` из модуля `src/shared/exceptions.py`. 3. Каждый базовый класс исключения содержит HTTP код, с которым будет отправлен ответ в случае если ошибка подобного класса (или подкласса этого класса) не будет обработана в роуте. 4. Все обработчики исключений верхнего уровня (т.е. обработчики исключений запускающиеся после того как исключение не было обработано в рамках роута) должны обрабатывать только исключения базовых типов - т.е. исключения из модуля `src/shared/exceptions.py`. Таким образом в рамках этой задачи необходимо изменить иерархию классов ошибок для соответствия требованиям, описанным выше.
- Loading branch information
1 parent
045eace
commit 8dcfb08
Showing
10 changed files
with
42 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters