Skip to content

Commit 37e4e65

Browse files
authored
Merge pull request #97 from Aidbox/base-fhir-error-handling
Handle BaseFHIRError in handlers
2 parents a5d4914 + da8a29a commit 37e4e65

5 files changed

Lines changed: 80 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.2.1
2+
3+
- Handle BaseFHIRError exceptions from fhir-py in operation handlers
4+
15
## 0.2.0
26

37
- Make pytest_plugin confiugurable via `aidbox_create_app` pytest settings for create_app function

aidbox_python_sdk/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__title__ = "aidbox-python-sdk"
2-
__version__ = "0.2.0"
2+
__version__ = "0.2.1"
33
__author__ = "beda.software"
44
__license__ = "None"
55
__copyright__ = "Copyright 2024 beda.software"

aidbox_python_sdk/handlers.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import asyncio
2+
import json
23
import logging
34
from typing import Any
45

56
from aiohttp import web
6-
from fhirpy.base.exceptions import OperationOutcome
7+
from fhirpy.base.exceptions import BaseFHIRError, OperationOutcome
78

89
from . import app_keys as ak
910

@@ -48,6 +49,12 @@ async def operation(request: web.Request, data: dict[str, Any]):
4849
return result
4950
except OperationOutcome as exc:
5051
return web.json_response(exc.resource, status=422)
52+
except BaseFHIRError as exc:
53+
try:
54+
payload = json.loads(str(exc))
55+
return web.json_response(payload, status=422)
56+
except (json.JSONDecodeError, TypeError):
57+
return web.Response(text=str(exc), status=422, content_type="text/plain")
5158

5259

5360
TYPES = {
@@ -59,10 +66,10 @@ async def operation(request: web.Request, data: dict[str, Any]):
5966
@routes.post("/aidbox")
6067
async def dispatch(request):
6168
logger.debug("Dispatch new request %s %s", request.method, request.url)
62-
json = await request.json()
63-
if "type" in json and json["type"] in TYPES:
64-
logger.debug("Dispatch to `%s` handler", json["type"])
65-
return await TYPES[json["type"]](request, json)
69+
data = await request.json()
70+
if "type" in data and data["type"] in TYPES:
71+
logger.debug("Dispatch to `%s` handler", data["type"])
72+
return await TYPES[data["type"]](request, data)
6673
req = {
6774
"method": request.method,
6875
"url": str(request.url),

main.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import asyncio
2+
import json
23
import logging
34
from datetime import datetime
45

56
import coloredlogs
67
from aiohttp import web
8+
from fhirpy.base.exceptions import BaseFHIRError, OperationOutcome
79
from sqlalchemy.sql.expression import select
810

911
from aidbox_python_sdk.db import DBProxy
@@ -119,7 +121,7 @@ async def daily_patient_report(operation, request):
119121
GET /Patient/$weekly-report
120122
GET /Patient/$daily-report
121123
"""
122-
patients = request.app["client"].resources("Patient")
124+
patients = request["app"]["client"].resources("Patient")
123125
async for p in patients:
124126
logging.debug(p.serialize())
125127
logging.debug("`daily_patient_report` operation handler")
@@ -133,7 +135,7 @@ async def get_app_ids(db: DBProxy):
133135
return await db.alchemy(select(app.c.id))
134136

135137

136-
@routes.get("/db_tests")
138+
@routes.get("/db-tests")
137139
async def db_tests(request):
138140
db = request.app["db"]
139141

@@ -151,3 +153,42 @@ async def db_tests(request):
151153
)
152154
async def observation_custom_op(operation, request):
153155
return {"message": "Observation custom operation response"}
156+
157+
158+
@sdk.operation(
159+
["POST"],
160+
["$operation-outcome-test"],
161+
)
162+
async def operation_outcome_test_op(operation, request):
163+
raise OperationOutcome(reason="test reason")
164+
165+
166+
@sdk.operation(
167+
["POST"],
168+
["$base-fhir-error-json-test"],
169+
)
170+
async def base_fhir_error_json_test_op(operation, request):
171+
raise BaseFHIRError(
172+
json.dumps(
173+
{
174+
"resourceType": "OperationOutcome",
175+
"id": "not-found",
176+
"text": {"status": "generated", "div": "Resource Patient/id not found"},
177+
"issue": [
178+
{
179+
"severity": "fatal",
180+
"code": "not-found",
181+
"diagnostics": "Resource Patient/id not found",
182+
}
183+
],
184+
}
185+
)
186+
)
187+
188+
189+
@sdk.operation(
190+
["POST"],
191+
["$base-fhir-error-text-test"],
192+
)
193+
async def base_fhir_error_text_test_op(operation, request):
194+
raise BaseFHIRError("plain")

tests/test_sdk.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import pytest
66
from fhirpathpy import evaluate
7+
from fhirpy.base.exceptions import OperationOutcome
78

89
import main
910
from aidbox_python_sdk.db import DBProxy
@@ -182,10 +183,28 @@ async def test_aidbox_db_fixture(client, aidbox_db: DBProxy, safe_db):
182183
"""
183184
Test that aidbox_db fixture works with isolated DB Proxy from app's instance
184185
"""
185-
response = await client.get("/db_tests")
186+
response = await client.get("/db-tests")
186187
assert response.status == 200
187188
json = await response.json()
188189
assert json == [{"id": "app-test"}]
189190

190191
app_ids = await main.get_app_ids(aidbox_db)
191192
assert app_ids == [{"id": "app-test"}]
193+
194+
195+
async def test_operation_base_fhir_error_json_test_op(aidbox_client):
196+
with pytest.raises(OperationOutcome) as exc:
197+
await aidbox_client.execute("/$base-fhir-error-json-test")
198+
assert exc.value.resource.get("issue")[0].get("diagnostics") == "Resource Patient/id not found"
199+
200+
201+
async def test_operation_base_fhir_error_text_test_op(aidbox_client):
202+
with pytest.raises(OperationOutcome) as exc:
203+
await aidbox_client.execute("/$base-fhir-error-text-test")
204+
assert exc.value.resource.get("issue")[0].get("diagnostics") == "plain"
205+
206+
207+
async def test_operation_outcome_test_op(aidbox_client):
208+
with pytest.raises(OperationOutcome) as exc:
209+
await aidbox_client.execute("/$operation-outcome-test")
210+
assert exc.value.resource.get("issue")[0].get("diagnostics") == "test reason"

0 commit comments

Comments
 (0)