Skip to content

Commit 96c9f7e

Browse files
committed
[NRL-1150] Switch ParseError to use loc if present
1 parent 677debf commit 96c9f7e

File tree

2 files changed

+95
-37
lines changed

2 files changed

+95
-37
lines changed

layer/nrlf/core/errors.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
from typing import List, Optional
22

33
from pydantic import ValidationError
4+
from pydantic_core import ErrorDetails
45

56
from nrlf.core.response import Response
67
from nrlf.core.types import CodeableConcept
78
from nrlf.producer.fhir.r4 import model as producer_model
89
from nrlf.producer.fhir.r4.model import OperationOutcome, OperationOutcomeIssue
910

1011

12+
def diag_for_error(error: ErrorDetails) -> str:
13+
if error["loc"]:
14+
return f"{error['loc'][0]}: {error['msg']}"
15+
else:
16+
return f"root: {error['msg']}"
17+
18+
19+
def expression_for_error(error: ErrorDetails) -> Optional[str]:
20+
return str(error["loc"][0] if error["loc"] else "root")
21+
22+
1123
class OperationOutcomeError(Exception):
1224
"""
1325
Will instantly trigger an OperationOutcome error response when raised
@@ -59,8 +71,8 @@ def from_validation_error(
5971
severity="error",
6072
code="invalid",
6173
details=details, # type: ignore
62-
diagnostics=f"{msg} ({error['loc']}: {error['msg']})",
63-
expression=[str(error["loc"])], # type: ignore
74+
diagnostics=f"{msg} ({diag_for_error(error)})",
75+
expression=[expression_for_error(error)], # type: ignore
6476
)
6577
for error in exc.errors()
6678
]

layer/nrlf/core/tests/test_request.py

Lines changed: 81 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -194,27 +194,26 @@ def test_parse_body_invalid_docref_json():
194194
response = error.value.response.model_dump()
195195

196196
assert response["statusCode"] == "400"
197-
assert response["body"] == json.dumps(
198-
{
199-
"resourceType": "OperationOutcome",
200-
"issue": [
201-
{
202-
"severity": "error",
203-
"code": "invalid",
204-
"details": {
205-
"coding": [
206-
{
207-
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
208-
"code": "MESSAGE_NOT_WELL_FORMED",
209-
"display": "Message not well formed",
210-
}
211-
],
212-
},
213-
"diagnostics": "Request body could not be parsed ((): Invalid JSON: control character (\\\\u0000-\\\\u001F) found while parsing a string at line 72 column 0)",
214-
}
215-
],
216-
}
217-
)
197+
assert json.loads(response["body"]) == {
198+
"resourceType": "OperationOutcome",
199+
"issue": [
200+
{
201+
"severity": "error",
202+
"code": "invalid",
203+
"details": {
204+
"coding": [
205+
{
206+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
207+
"code": "MESSAGE_NOT_WELL_FORMED",
208+
"display": "Message not well formed",
209+
}
210+
],
211+
},
212+
"diagnostics": "Request body could not be parsed (root: Invalid JSON: control character (\\u0000-\\u001F) found while parsing a string at line 72 column 0)",
213+
"expression": ["root"],
214+
}
215+
],
216+
}
218217

219218

220219
def test_parse_body_invalid_json():
@@ -224,10 +223,10 @@ def test_parse_body_invalid_json():
224223
with pytest.raises(ParseError) as error:
225224
parse_body(model, body)
226225

227-
response = error.value.response
226+
response = error.value.response.model_dump()
228227

229-
assert response.statusCode == "400"
230-
assert json.loads(response.body) == {
228+
assert response["statusCode"] == "400"
229+
assert json.loads(response["body"]) == {
231230
"resourceType": "OperationOutcome",
232231
"issue": [
233232
{
@@ -240,10 +239,56 @@ def test_parse_body_invalid_json():
240239
"code": "MESSAGE_NOT_WELL_FORMED",
241240
"display": "Message not well formed",
242241
}
243-
],
242+
]
244243
},
245-
"diagnostics": "",
246-
}
244+
"diagnostics": "Request body could not be parsed (resourceType: Field required)",
245+
"expression": ["resourceType"],
246+
},
247+
{
248+
"severity": "error",
249+
"code": "invalid",
250+
"details": {
251+
"coding": [
252+
{
253+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
254+
"code": "MESSAGE_NOT_WELL_FORMED",
255+
"display": "Message not well formed",
256+
}
257+
]
258+
},
259+
"diagnostics": "Request body could not be parsed (status: Field required)",
260+
"expression": ["status"],
261+
},
262+
{
263+
"severity": "error",
264+
"code": "invalid",
265+
"details": {
266+
"coding": [
267+
{
268+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
269+
"code": "MESSAGE_NOT_WELL_FORMED",
270+
"display": "Message not well formed",
271+
}
272+
]
273+
},
274+
"diagnostics": "Request body could not be parsed (type: Input should be an object)",
275+
"expression": ["type"],
276+
},
277+
{
278+
"severity": "error",
279+
"code": "invalid",
280+
"details": {
281+
"coding": [
282+
{
283+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
284+
"code": "MESSAGE_NOT_WELL_FORMED",
285+
"display": "Message not well formed",
286+
}
287+
]
288+
},
289+
"diagnostics": "Request body could not be parsed (content: Field required)",
290+
"expression": ["content"],
291+
},
247292
],
248293
}
249294

@@ -252,13 +297,13 @@ def test_parse_body_not_json():
252297
model = DocumentReference
253298
body = "is not json"
254299

255-
with pytest.raises(OperationOutcomeError) as error:
300+
with pytest.raises(ParseError) as error:
256301
parse_body(model, body)
257302

258-
exc = error.value
303+
response = error.value.response
259304

260-
assert exc.status_code == "400"
261-
assert exc.operation_outcome.model_dump(exclude_none=True) == {
305+
assert response.statusCode == "400"
306+
assert json.loads(response.body) == {
262307
"resourceType": "OperationOutcome",
263308
"issue": [
264309
{
@@ -268,12 +313,13 @@ def test_parse_body_not_json():
268313
"coding": [
269314
{
270315
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
271-
"code": "INVALID_PARAMETER",
272-
"display": "The parameter value is not valid",
316+
"code": "MESSAGE_NOT_WELL_FORMED",
317+
"display": "Message not well formed",
273318
}
274-
],
319+
]
275320
},
276-
"diagnostics": "Invalid query parameter",
321+
"diagnostics": "Request body could not be parsed (root: Invalid JSON: expected value at line 1 column 1)",
322+
"expression": ["root"],
277323
}
278324
],
279325
}

0 commit comments

Comments
 (0)