-
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.
Merge pull request #42 from cuenca-mx/knox
error handlers + `FastAgaveError`
- Loading branch information
Showing
9 changed files
with
113 additions
and
17 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 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,31 @@ | ||
from typing import Dict | ||
from typing import Dict, NoReturn | ||
|
||
from cuenca_validations.errors import WrongCredsError | ||
|
||
from fast_agave.blueprints import RestApiBlueprint | ||
from fast_agave.exc import UnauthorizedError | ||
|
||
app = RestApiBlueprint() | ||
|
||
|
||
@app.get('/healthy_auth') | ||
def health_auth_check() -> Dict: | ||
return dict(greeting="I'm authenticated and healthy !!!") | ||
|
||
|
||
@app.get('/raise_cuenca_errors') | ||
def raise_cuenca_errors() -> NoReturn: | ||
raise WrongCredsError('you are not lucky enough!') | ||
|
||
|
||
@app.get('/raise_fast_agave_errors') | ||
def raise_fast_agave_errors() -> NoReturn: | ||
raise UnauthorizedError('nice try!') | ||
|
||
|
||
@app.get('/you_shall_not_pass') | ||
def you_shall_not_pass() -> None: | ||
# Este endpoint nunca será ejecutado | ||
# La prueba de este endpoint hace un mock a nivel middleware | ||
# para responder con un `UnauthorizedError` | ||
... |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,32 @@ | ||
from dataclasses import dataclass | ||
|
||
from fastapi import HTTPException | ||
|
||
@dataclass | ||
class FastAgaveError(Exception): | ||
error: str | ||
status_code: int | ||
|
||
|
||
@dataclass | ||
class Error(HTTPException): | ||
def __init__(self, detail=''): | ||
super().__init__(status_code=self.status_code, detail=detail) | ||
class BadRequestError(FastAgaveError): | ||
status_code: int = 400 | ||
|
||
|
||
class BadRequestError(Error): | ||
status_code = 400 | ||
@dataclass | ||
class UnauthorizedError(FastAgaveError): | ||
status_code: int = 401 | ||
|
||
|
||
class UnauthorizedError(Error): | ||
status_code = 401 | ||
@dataclass | ||
class ForbiddenError(FastAgaveError): | ||
status_code: int = 403 | ||
|
||
|
||
class ForbiddenError(Error): | ||
status_code = 403 | ||
@dataclass | ||
class NotFoundError(FastAgaveError): | ||
status_code: int = 404 | ||
|
||
|
||
class NotFoundError(Error): | ||
status_code = 404 | ||
@dataclass | ||
class FastAgaveViewError(FastAgaveError): | ||
status_code: int = 500 |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .error_handlers import FastAgaveErrorHandler | ||
|
||
__all__ = ['FastAgaveErrorHandler'] |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from cuenca_validations.errors import CuencaError | ||
from fastapi import Request, Response | ||
from fastapi.responses import JSONResponse | ||
from starlette.middleware.base import ( | ||
BaseHTTPMiddleware, | ||
RequestResponseEndpoint, | ||
) | ||
|
||
from fast_agave.exc import FastAgaveError | ||
|
||
|
||
class FastAgaveErrorHandler(BaseHTTPMiddleware): | ||
async def dispatch( | ||
self, request: Request, call_next: RequestResponseEndpoint | ||
) -> Response: | ||
try: | ||
return await call_next(request) | ||
except CuencaError as exc: | ||
return JSONResponse( | ||
status_code=exc.status_code, | ||
content=dict( | ||
code=exc.code, | ||
error=str(exc), | ||
), | ||
) | ||
except FastAgaveError as exc: | ||
return JSONResponse( | ||
status_code=exc.status_code, content=dict(error=exc.error) | ||
) |
Empty file.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
__version__ = '0.0.3' | ||
__version__ = '0.1.0' |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,38 @@ | ||
from unittest.mock import AsyncMock | ||
|
||
from _pytest.monkeypatch import MonkeyPatch | ||
from fastapi.testclient import TestClient | ||
|
||
from examples.middlewares.authed import AuthedMiddleware | ||
from fast_agave.exc import UnauthorizedError | ||
|
||
|
||
def test_iam_healthy(client: TestClient) -> None: | ||
resp = client.get('/') | ||
assert resp.status_code == 200 | ||
assert resp.json() == dict(greeting="I'm healthy!!!") | ||
|
||
|
||
def test_cuenca_error_handler(client: TestClient) -> None: | ||
resp = client.get('/raise_cuenca_errors') | ||
assert resp.status_code == 401 | ||
assert resp.json() == dict(error='you are not lucky enough!', code=101) | ||
|
||
|
||
def test_fast_agave_error_handler(client: TestClient) -> None: | ||
resp = client.get('/raise_fast_agave_errors') | ||
assert resp.status_code == 401 | ||
assert resp.json() == dict(error='nice try!') | ||
|
||
|
||
def test_fast_agave_error_handler_from_middleware( | ||
client: TestClient, monkeypatch: MonkeyPatch | ||
) -> None: | ||
monkeypatch.setattr( | ||
AuthedMiddleware, | ||
'authorize', | ||
AsyncMock(side_effect=UnauthorizedError('come back to the shadows!')), | ||
) | ||
resp = client.get('/you_shall_not_pass') | ||
assert resp.status_code == 401 | ||
assert resp.json() == dict(error='come back to the shadows!') |