Skip to content

Commit 28baf6d

Browse files
authored
Tidy up FastAPI route functions (#112)
- return objects directly instead of wrapping in response classes FastAPI will automatically encode objects as JSON when they are returned directly. This also means that we can remove orjson -- one less dependency to manage - use multiple route decorators for monitor functions with same responses - remove extraneous route function parameters Other small fixes: - Ignore bugzilla and atlassian types through pyproject.toml - Add ServiceHealth type - Slightly refactor "heartbeat" logic
1 parent 07f2f3d commit 28baf6d

File tree

5 files changed

+26
-102
lines changed

5 files changed

+26
-102
lines changed

poetry.lock

Lines changed: 1 addition & 49 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ dockerflow = "2022.1.0"
1818
Jinja2 = "^3.0.3"
1919
pydantic-yaml = {extras = ["pyyaml","ruamel"], version = "^0.6.1"}
2020
sentry-sdk = "^1.5.7"
21-
orjson = "^3.7.7"
2221

2322

2423
[tool.poetry.dev-dependencies]
@@ -74,7 +73,7 @@ python_version = "3.10"
7473
warn_return_any = true
7574

7675
[[tool.mypy.overrides]]
77-
module = ["ruamel"]
76+
module = ["ruamel", "bugzilla", "atlassian"]
7877
ignore_missing_imports = true
7978

8079
[tool.coverage]

src/app/api.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import uvicorn # type: ignore
1212
from fastapi import Body, Depends, FastAPI, Request
1313
from fastapi.encoders import jsonable_encoder
14-
from fastapi.responses import HTMLResponse, ORJSONResponse
14+
from fastapi.responses import HTMLResponse
1515
from fastapi.staticfiles import StaticFiles
1616
from fastapi.templating import Jinja2Templates
1717
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
@@ -49,7 +49,7 @@
4949

5050

5151
@app.get("/", include_in_schema=False)
52-
def root(request: Request):
52+
def root():
5353
"""Expose key configuration"""
5454
return {
5555
"title": app.title,
@@ -98,9 +98,9 @@ def bugzilla_webhook(
9898
"""API endpoint that Bugzilla Webhook Events request"""
9999
try:
100100
result = execute_action(request, actions, settings)
101-
return ORJSONResponse(content=result, status_code=200)
101+
return result
102102
except IgnoreInvalidRequestError as exception:
103-
return ORJSONResponse(content={"error": str(exception)}, status_code=200)
103+
return {"error": str(exception)}
104104

105105

106106
@app.get("/whiteboard_tags/")

src/app/monitor.py

Lines changed: 9 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,29 @@
11
"""
22
Router dedicated to Dockerflow APIs
33
"""
4-
from typing import Dict
5-
6-
from fastapi import APIRouter, Depends, Request
7-
from fastapi.responses import ORJSONResponse
4+
from fastapi import APIRouter, Response
85

96
from src.app import environment
107
from src.jbi.services import jbi_service_health_map
118

129
api_router = APIRouter(tags=["Monitor"])
1310

1411

15-
def heartbeat(request: Request, settings: environment.Settings):
16-
"""Return status of backing services, as required by Dockerflow."""
17-
data: Dict = {**jbi_service_health_map()}
18-
status_code = 200
19-
for _, health in data.items():
20-
if not health.get("up"):
21-
status_code = 503
22-
23-
return ORJSONResponse(content=data, status_code=status_code)
24-
25-
2612
@api_router.get("/__heartbeat__")
27-
def get_heartbeat(
28-
request: Request,
29-
settings: environment.Settings = Depends(environment.get_settings),
30-
):
31-
"""Dockerflow API for heartbeat: GET"""
32-
return heartbeat(request, settings)
33-
34-
3513
@api_router.head("/__heartbeat__")
36-
def head_heartbeat(
37-
request: Request,
38-
settings: environment.Settings = Depends(environment.get_settings),
39-
):
40-
"""Dockerflow API for heartbeat: HEAD"""
41-
return heartbeat(request, settings)
42-
43-
44-
def lbheartbeat(request: Request):
45-
"""Return response when application is running, as required by Dockerflow."""
46-
return {"status": "OK"}
14+
def heartbeat(response: Response):
15+
"""Return status of backing services, as required by Dockerflow."""
16+
health_map = jbi_service_health_map()
17+
if not all(health["up"] for health in health_map.values()):
18+
response.status_code = 503
19+
return health_map
4720

4821

4922
@api_router.get("/__lbheartbeat__")
50-
def get_lbheartbeat(request: Request):
51-
"""Dockerflow API for lbheartbeat: GET"""
52-
return lbheartbeat(request)
53-
54-
5523
@api_router.head("/__lbheartbeat__")
56-
def head_lbheartbeat(request: Request):
24+
def lbheartbeat():
5725
"""Dockerflow API for lbheartbeat: HEAD"""
58-
return lbheartbeat(request)
26+
return {"status": "OK"}
5927

6028

6129
@api_router.get("/__version__")

src/jbi/services.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
"""Services and functions that can be used to create custom actions"""
2-
import bugzilla as rh_bugzilla # type: ignore
3-
from atlassian import Jira # type: ignore
2+
from typing import TypedDict
3+
4+
import bugzilla as rh_bugzilla
5+
from atlassian import Jira
46

57
from src.app import environment
68

79
settings = environment.get_settings()
810

911

12+
ServiceHealth = TypedDict("ServiceHealth", {"up": bool})
13+
14+
1015
def get_jira():
1116
"""Get atlassian Jira Service"""
1217
return Jira(
@@ -24,18 +29,18 @@ def get_bugzilla():
2429
)
2530

2631

27-
def bugzilla_check_health():
32+
def bugzilla_check_health() -> ServiceHealth:
2833
"""Check health for Bugzilla Service"""
2934
bugzilla = get_bugzilla()
30-
health = {"up": bugzilla.logged_in}
35+
health: ServiceHealth = {"up": bugzilla.logged_in}
3136
return health
3237

3338

34-
def jira_check_health():
39+
def jira_check_health() -> ServiceHealth:
3540
"""Check health for Jira Service"""
3641
jira = get_jira()
3742
server_info = jira.get_server_info(True)
38-
health = {"up": server_info is not None}
43+
health: ServiceHealth = {"up": server_info is not None}
3944
return health
4045

4146

0 commit comments

Comments
 (0)