Extended HTTPException and Response with error handling

pull/220/head
kompotkot 2021-09-02 10:49:23 +00:00
rodzic 120b6a952c
commit 6ac9df74aa
7 zmienionych plików z 94 dodań i 74 usunięć

Wyświetl plik

@ -1,10 +1,11 @@
import logging
from typing import Awaitable, Callable, Dict, Optional
from typing import Any, Awaitable, Callable, Dict, Optional
from bugout.data import BugoutUser
from bugout.exceptions import BugoutResponseException
from fastapi import HTTPException, Request, Response
from starlette.background import BackgroundTask
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi import Request, Response
from .reporter import reporter
from .settings import MOONSTREAM_APPLICATION_ID, bugout_client as bc
@ -12,6 +13,44 @@ from .settings import MOONSTREAM_APPLICATION_ID, bugout_client as bc
logger = logging.getLogger(__name__)
class MoonstreamResponse(Response):
"""
Extended Response to handle 500 Internal server errors
and send crash reports.
"""
def __init__(
self,
content: Any = None,
status_code: int = 200,
headers: dict = None,
media_type: str = None,
background: BackgroundTask = None,
internal_error: Exception = None,
):
super().__init__(content, status_code, headers, media_type, background)
if internal_error is not None:
reporter.error_report(internal_error)
class MoonstreamHTTPException(HTTPException):
"""
Extended HTTPException to handle 500 Internal server errors
and send crash reports.
"""
def __init__(
self,
status_code: int,
detail: Any = None,
headers: Optional[Dict[str, Any]] = None,
internal_error: Exception = None,
):
super().__init__(status_code, detail, headers)
if internal_error is not None:
reporter.error_report(internal_error)
class BroodAuthMiddleware(BaseHTTPMiddleware):
"""
Checks the authorization header on the request. If it represents a verified Brood user,
@ -62,8 +101,9 @@ class BroodAuthMiddleware(BaseHTTPMiddleware):
return Response(status_code=e.status_code, content=e.detail)
except Exception as e:
logger.error(f"Error processing Brood response: {str(e)}")
reporter.error_report(e)
return Response(status_code=500, content="Internal server error")
return MoonstreamResponse(
status_code=500, content="Internal server error", internal_error=e
)
request.state.user = user
request.state.token = user_token

Wyświetl plik

@ -3,15 +3,14 @@ from typing import Dict, List, Optional
from sqlalchemy.sql.expression import true
from fastapi import FastAPI, Depends, Query, HTTPException
from fastapi import FastAPI, Depends, Query
from fastapi.middleware.cors import CORSMiddleware
from moonstreamdb.db import yield_db_session
from sqlalchemy.orm import Session
from .. import actions
from .. import data
from ..middleware import BroodAuthMiddleware
from ..reporter import reporter
from ..middleware import BroodAuthMiddleware, MoonstreamHTTPException
from ..settings import DOCS_TARGET_PATH, ORIGINS, DOCS_PATHS
from ..version import MOONSTREAM_VERSION
@ -74,16 +73,15 @@ async def addresses_labels_bulk_handler(
about known addresses.
"""
if limit > 100:
raise HTTPException(
raise MoonstreamHTTPException(
status_code=406, detail="The limit cannot exceed 100 addresses"
)
try:
addresses_response = actions.get_address_labels(
db_session=db_session, start=start, limit=limit, addresses=addresses
)
except Exception as err:
logger.error(f"Unable to get info about Ethereum addresses {err}")
reporter.error_report(err)
raise HTTPException(status_code=500)
except Exception as e:
logger.error(f"Unable to get info about Ethereum addresses {e}")
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return addresses_response

Wyświetl plik

@ -5,14 +5,14 @@ import logging
from typing import Dict, List, Optional
from bugout.data import BugoutResource
from fastapi import FastAPI, HTTPException, Request, Query, Depends
from fastapi import FastAPI, Request, Query, Depends
from fastapi.middleware.cors import CORSMiddleware
from moonstreamdb import db
from sqlalchemy.orm import Session
from .. import data
from ..middleware import BroodAuthMiddleware
from ..middleware import BroodAuthMiddleware, MoonstreamHTTPException
from ..providers import (
ReceivingEventsException,
event_providers,
@ -21,7 +21,6 @@ from ..providers import (
next_event,
previous_event,
)
from ..reporter import reporter
from ..settings import (
DOCS_TARGET_PATH,
MOONSTREAM_ADMIN_ACCESS_TOKEN,
@ -137,12 +136,10 @@ async def stream_handler(
)
except ReceivingEventsException as e:
logger.error("Error receiving events from provider")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
except Exception as e:
logger.error("Unable to get events")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
response = data.GetEventsResponse(stream_boundary=stream_boundary, events=events)
return response
@ -182,12 +179,10 @@ async def latest_events_handler(
)
except ReceivingEventsException as e:
logger.error("Error receiving events from provider")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
except Exception as e:
logger.error("Unable to get latest events")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return events
@ -239,12 +234,10 @@ async def next_event_handler(
)
except ReceivingEventsException as e:
logger.error("Error receiving events from provider")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
except Exception as e:
logger.error("Unable to get next events")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return event
@ -296,11 +289,9 @@ async def previous_event_handler(
)
except ReceivingEventsException as e:
logger.error("Error receiving events from provider")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
except Exception as e:
logger.error("Unable to get previous events")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return event

Wyświetl plik

@ -6,12 +6,12 @@ from typing import Dict, List, Optional
from bugout.data import BugoutResource, BugoutResources
from bugout.exceptions import BugoutResponseException
from fastapi import FastAPI, HTTPException, Request, Form
from fastapi import FastAPI, Request, Form
from fastapi.middleware.cors import CORSMiddleware
from ..admin import subscription_types
from .. import data
from ..middleware import BroodAuthMiddleware
from ..middleware import BroodAuthMiddleware, MoonstreamHTTPException
from ..reporter import reporter
from ..settings import (
DOCS_TARGET_PATH,
@ -78,7 +78,7 @@ async def add_subscription_handler(
]
if subscription_type_id not in available_subscription_type_ids:
raise HTTPException(
raise MoonstreamHTTPException(
status_code=404,
detail=f"Invalid subscription type: {subscription_type_id}.",
)
@ -100,10 +100,11 @@ async def add_subscription_handler(
application_id=MOONSTREAM_APPLICATION_ID,
resource_data=resource_data,
)
except BugoutResponseException as e:
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
logger.error(f"Error creating subscription resource: {str(e)}")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return data.SubscriptionResourceData(
id=str(resource.id),
@ -128,11 +129,10 @@ async def delete_subscription_handler(request: Request, subscription_id: str):
try:
deleted_resource = bc.delete_resource(token=token, resource_id=subscription_id)
except BugoutResponseException as e:
raise HTTPException(status_code=e.status_code, detail=e.detail)
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
logger.error(f"Error deleting subscription: {str(e)}")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return data.SubscriptionResourceData(
id=str(deleted_resource.id),
@ -156,12 +156,14 @@ async def get_subscriptions_handler(request: Request) -> data.SubscriptionsListR
}
try:
resources: BugoutResources = bc.list_resources(token=token, params=params)
except BugoutResponseException as e:
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
logger.error(
f"Error listing subscriptions for user ({request.user.id}) with token ({request.state.token}), error: {str(e)}"
)
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return data.SubscriptionsListResponse(
subscriptions=[
@ -211,11 +213,10 @@ async def update_subscriptions_handler(
).dict(),
)
except BugoutResponseException as e:
raise HTTPException(status_code=e.status_code, detail=e.detail)
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
logger.error(f"Error getting user subscriptions: {str(e)}")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return data.SubscriptionResourceData(
id=str(resource.id),
@ -241,9 +242,10 @@ async def list_subscription_types() -> data.SubscriptionTypesListResponse:
data.SubscriptionTypeResourceData.validate(resource.resource_data)
for resource in response.resources
]
except BugoutResponseException as e:
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
logger.error(f"Error reading subscription types from Brood API: {str(e)}")
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return data.SubscriptionTypesListResponse(subscription_types=results)

Wyświetl plik

@ -7,16 +7,10 @@ import uuid
from bugout.data import BugoutToken, BugoutUser
from bugout.exceptions import BugoutResponseException
from fastapi import (
FastAPI,
Form,
HTTPException,
Request,
)
from fastapi import FastAPI, Form, Request
from fastapi.middleware.cors import CORSMiddleware
from ..middleware import BroodAuthMiddleware
from ..reporter import reporter
from ..middleware import BroodAuthMiddleware, MoonstreamHTTPException
from ..settings import (
MOONSTREAM_APPLICATION_ID,
DOCS_TARGET_PATH,
@ -76,10 +70,9 @@ async def create_user_handler(
application_id=MOONSTREAM_APPLICATION_ID,
)
except BugoutResponseException as e:
raise HTTPException(status_code=e.status_code, detail=e.detail)
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return user
@ -94,10 +87,9 @@ async def restore_password_handler(email: str = Form(...)) -> Dict[str, Any]:
try:
response = bc.restore_password(email=email)
except BugoutResponseException as e:
raise HTTPException(status_code=e.status_code, detail=e.detail)
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return response
@ -108,10 +100,9 @@ async def reset_password_handler(
try:
response = bc.reset_password(reset_id=reset_id, new_password=new_password)
except BugoutResponseException as e:
raise HTTPException(status_code=e.status_code, detail=e.detail)
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return response
@ -125,10 +116,9 @@ async def change_password_handler(
token=token, current_password=current_password, new_password=new_password
)
except BugoutResponseException as e:
raise HTTPException(status_code=e.status_code, detail=e.detail)
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return user
@ -141,10 +131,9 @@ async def delete_user_handler(
try:
user = bc.delete_user(token=token, user_id=user.id, password=password)
except BugoutResponseException as e:
raise HTTPException(status_code=e.status_code, detail=e.detail)
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return user
@ -159,12 +148,11 @@ async def login_handler(
application_id=MOONSTREAM_APPLICATION_ID,
)
except BugoutResponseException as e:
raise HTTPException(
raise MoonstreamHTTPException(
status_code=e.status_code, detail=f"Error from Brood API: {e.detail}"
)
except Exception as e:
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return token
@ -174,8 +162,7 @@ async def logout_handler(request: Request) -> uuid.UUID:
try:
token_id: uuid.UUID = bc.revoke_token(token=token)
except BugoutResponseException as e:
raise HTTPException(status_code=e.status_code, detail=e.detail)
raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
reporter.error_report(e)
raise HTTPException(status_code=500)
raise MoonstreamHTTPException(status_code=500, internal_error=e)
return token_id

Wyświetl plik

@ -29,5 +29,6 @@ toml==0.10.2
tomli==1.0.4
types-python-dateutil==0.1.6
typing-extensions==3.10.0.0
types-requests==2.25.6
urllib3==1.26.6
uvicorn==0.14.0

Wyświetl plik

@ -18,6 +18,7 @@ setup(
"python-dateutil",
"uvicorn",
"types-python-dateutil",
"types-requests",
],
extras_require={
"dev": ["black", "mypy"],