[New Feature] Rest API implementation to showcase the OpenDBM features
This commit is contained in:
0
rest_api/app/utils/__init__.py
Normal file
0
rest_api/app/utils/__init__.py
Normal file
51
rest_api/app/utils/app_exceptions.py
Normal file
51
rest_api/app/utils/app_exceptions.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from fastapi import Request
|
||||
from starlette.responses import JSONResponse
|
||||
|
||||
|
||||
class AppExceptionCase(Exception):
|
||||
def __init__(self, status_code: int, context: dict):
|
||||
self.exception_case = self.__class__.__name__
|
||||
self.status_code = status_code
|
||||
self.context = context
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
f"<AppException {self.exception_case} - "
|
||||
+ f"status_code={self.status_code} - context={self.context}>"
|
||||
)
|
||||
|
||||
|
||||
async def app_exception_handler(request: Request, exc: AppExceptionCase):
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content={
|
||||
"app_exception": exc.exception_case,
|
||||
"context": exc.context,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class AppException(object):
|
||||
class FooCreateItem(AppExceptionCase):
|
||||
def __init__(self, context: dict = None):
|
||||
"""
|
||||
Item creation failed
|
||||
"""
|
||||
status_code = 500
|
||||
AppExceptionCase.__init__(self, status_code, context)
|
||||
|
||||
class FooGetItem(AppExceptionCase):
|
||||
def __init__(self, context: dict = None):
|
||||
"""
|
||||
Item not found
|
||||
"""
|
||||
status_code = 404
|
||||
AppExceptionCase.__init__(self, status_code, context)
|
||||
|
||||
class FooItemRequiresAuth(AppExceptionCase):
|
||||
def __init__(self, context: dict = None):
|
||||
"""
|
||||
Item is not public and requires auth
|
||||
"""
|
||||
status_code = 401
|
||||
AppExceptionCase.__init__(self, status_code, context)
|
||||
@@ -0,0 +1,4 @@
|
||||
from utils.app_exceptions import AppException
|
||||
|
||||
print([e for e in dir(AppException) if "__" not in e])
|
||||
# ['FooCreateItem', 'FooGetItem', 'FooItemRequiresAuth']
|
||||
22
rest_api/app/utils/request_exceptions.py
Normal file
22
rest_api/app/utils/request_exceptions.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
|
||||
from starlette.exceptions import HTTPException
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse
|
||||
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
|
||||
|
||||
|
||||
async def http_exception_handler(
|
||||
request: Request, exc: HTTPException
|
||||
) -> JSONResponse:
|
||||
return JSONResponse({"detail": exc.detail}, status_code=exc.status_code)
|
||||
|
||||
|
||||
async def request_validation_exception_handler(
|
||||
request: Request, exc: RequestValidationError
|
||||
) -> JSONResponse:
|
||||
return JSONResponse(
|
||||
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
content={"detail": jsonable_encoder(exc.errors())},
|
||||
)
|
||||
47
rest_api/app/utils/service_result.py
Normal file
47
rest_api/app/utils/service_result.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from loguru import logger
|
||||
import inspect
|
||||
|
||||
from utils.app_exceptions import AppExceptionCase
|
||||
|
||||
|
||||
class ServiceResult(object):
|
||||
def __init__(self, arg):
|
||||
if isinstance(arg, AppExceptionCase):
|
||||
self.success = False
|
||||
self.exception_case = arg.exception_case
|
||||
self.status_code = arg.status_code
|
||||
else:
|
||||
self.success = True
|
||||
self.exception_case = None
|
||||
self.status_code = None
|
||||
self.value = arg
|
||||
|
||||
def __str__(self):
|
||||
if self.success:
|
||||
return "[Success]"
|
||||
return f'[Exception] "{self.exception_case}"'
|
||||
|
||||
def __repr__(self):
|
||||
if self.success:
|
||||
return "<ServiceResult Success>"
|
||||
return f"<ServiceResult AppException {self.exception_case}>"
|
||||
|
||||
def __enter__(self):
|
||||
return self.value
|
||||
|
||||
def __exit__(self, *kwargs):
|
||||
pass
|
||||
|
||||
|
||||
def caller_info() -> str:
|
||||
info = inspect.getframeinfo(inspect.stack()[2][0])
|
||||
return f"{info.filename}:{info.function}:{info.lineno}"
|
||||
|
||||
|
||||
def handle_result(result: ServiceResult):
|
||||
if not result.success:
|
||||
with result as exception:
|
||||
logger.error(f"{exception} | caller={caller_info()}")
|
||||
raise exception
|
||||
with result as result:
|
||||
return result
|
||||
Reference in New Issue
Block a user