forked from ExpDev07/coronavirus-tracker-api
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
121 lines (96 loc) · 3.05 KB
/
main.py
File metadata and controls
121 lines (96 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"""
app.main.py
"""
import logging
import pydantic
import sentry_sdk
import uvicorn
from fastapi import FastAPI, Request, Response
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.responses import JSONResponse
from scout_apm.async_.starlette import ScoutMiddleware
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
from .config import get_settings
from .data import data_source
from .routers import V1, V2
from .utils.httputils import setup_client_session, teardown_client_session
# ############
# FastAPI App
# ############
LOGGER = logging.getLogger("api")
SETTINGS = get_settings()
if SETTINGS.sentry_dsn: # pragma: no cover
sentry_sdk.init(dsn=SETTINGS.sentry_dsn)
APP = FastAPI(
title="Coronavirus Tracker",
description=(
"API for tracking the global coronavirus (COVID-19, SARS-CoV-2) outbreak."
" Project page: https://github.com/ExpDev07/coronavirus-tracker-api."
),
version="2.0.4",
docs_url="/",
redoc_url="/docs",
on_startup=[setup_client_session],
on_shutdown=[teardown_client_session],
)
# #####################
# Middleware
#######################
# Scout APM
if SETTINGS.scout_name: # pragma: no cover
LOGGER.info(f"Adding Scout APM middleware for `{SETTINGS.scout_name}`")
APP.add_middleware(ScoutMiddleware)
else:
LOGGER.debug("No SCOUT_NAME config")
# Sentry Error Tracking
if SETTINGS.sentry_dsn: # pragma: no cover
LOGGER.info("Adding Sentry middleware")
APP.add_middleware(SentryAsgiMiddleware)
# Enable CORS.
APP.add_middleware(
CORSMiddleware,
allow_credentials=True,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
APP.add_middleware(GZipMiddleware, minimum_size=1000)
@APP.middleware("http")
async def add_datasource(request: Request, call_next):
"""
Attach the data source to the request.state.
"""
# Retrieve the datas ource from query param.
source = data_source(request.query_params.get("source", default="jhu"))
# Abort with 404 if source cannot be found.
if not source:
return Response("The provided data-source was not found.", status_code=404)
# Attach source to request.
request.state.source = source
# Move on...
LOGGER.debug(f"source provided: {source.__class__.__name__}")
response = await call_next(request)
return response
# ################
# Exception Handler
# ################
@APP.exception_handler(pydantic.error_wrappers.ValidationError)
async def handle_validation_error(
request: Request, exc: pydantic.error_wrappers.ValidationError
): # pylint: disable=unused-argument
"""
Handles validation errors.
"""
return JSONResponse({"message": exc.errors()}, status_code=422)
# ################
# Routing
# ################
# Include routers.
APP.include_router(V1, prefix="", tags=["v1"])
APP.include_router(V2, prefix="/v2", tags=["v2"])
# Running of app.
if __name__ == "__main__":
uvicorn.run(
"app.main:APP", host="127.0.0.1", port=SETTINGS.port, log_level="info",
)