Skip to content

Commit 717b2c3

Browse files
Merge branch 'develop' into feature/eema1-NRL-1205-categoryIsntIgnoredInSearch
2 parents aba6214 + 380b6ec commit 717b2c3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+947
-176
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,9 @@ $ make test-smoke-public
324324

325325
If the API changes, the API documentation needs to be updated in the appropriate API repo. This is done by making changes to the API specification `.yaml` files in each repo.
326326

327-
For Consumer API changes, update (NRL Consumer API - consumer.yaml)[https://github.com/NHSDigital/nrl-consumer-api/blob/master/specification/record-locator/consumer.yaml]
327+
For Consumer API changes, update [NRL Consumer API - consumer.yaml](https://github.com/NHSDigital/nrl-consumer-api/blob/master/specification/record-locator/consumer.yaml)
328328

329-
For Producer API changes, update (NRL Producer API - producer.yaml)[https://github.com/NHSDigital/nrl-producer-api/blob/master/specification/record-locator/producer.yaml]
329+
For Producer API changes, update [NRL Producer API - producer.yaml](https://github.com/NHSDigital/nrl-producer-api/blob/master/specification/record-locator/producer.yaml)
330330

331331
Changes to the files in those repos will be reflected when each one is released. See the documentation in each repo for this process.
332332

api/consumer/searchDocumentReference/search_document_reference.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
from pydantic import ValidationError
22

3-
from nrlf.consumer.fhir.r4.model import Bundle, DocumentReference
3+
from nrlf.consumer.fhir.r4.model import (
4+
Bundle,
5+
DocumentReference,
6+
OperationOutcome,
7+
OperationOutcomeIssue,
8+
)
49
from nrlf.core.codes import SpineErrorConcept
510
from nrlf.core.config import Config
611
from nrlf.core.decorators import request_handler
712
from nrlf.core.dynamodb.repository import DocumentPointerRepository
8-
from nrlf.core.errors import OperationOutcomeError
913
from nrlf.core.logger import LogReference, logger
1014
from nrlf.core.model import ConnectionMetadata, ConsumerRequestParams
1115
from nrlf.core.response import Response, SpineErrorResponse
@@ -120,13 +124,21 @@ def handler(
120124
logger.log(
121125
LogReference.CONSEARCH005, error=str(exc), document=result.document
122126
)
123-
raise OperationOutcomeError(
124-
status_code="500",
125-
severity="error",
126-
code="exception",
127-
details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"),
128-
diagnostics="An error occurred whilst parsing the document reference search results",
129-
) from exc
127+
operation_outcome = OperationOutcome(
128+
resourceType="OperationOutcome",
129+
issue=[
130+
OperationOutcomeIssue(
131+
severity="error",
132+
code="exception",
133+
details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"),
134+
diagnostics="An error occurred whilst parsing the document reference search results",
135+
)
136+
],
137+
)
138+
bundle["total"] += 1
139+
bundle["entry"].append(
140+
{"resource": operation_outcome.model_dump(exclude_none=True)}
141+
)
130142

131143
response = Response.from_resource(Bundle.model_validate(bundle))
132144
logger.log(LogReference.CONSEARCH999)

api/consumer/searchDocumentReference/tests/test_search_document_reference_consumer.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -723,10 +723,13 @@ def test_search_document_reference_invalid_category(
723723
def test_search_document_reference_invalid_json(repository: DocumentPointerRepository):
724724
doc_ref = load_document_reference("Y05868-736253002-Valid")
725725
doc_pointer = DocumentPointer.from_document_reference(doc_ref)
726-
doc_pointer.document = "invalid json"
727-
728726
repository.create(doc_pointer)
729727

728+
doc_pointer_invalid = DocumentPointer.from_document_reference(doc_ref)
729+
doc_pointer_invalid.id = "Y05868-11111-99999-999992"
730+
doc_pointer_invalid.document = "invalid json"
731+
732+
repository.create(doc_pointer_invalid)
730733
event = create_test_api_gateway_event(
731734
headers=create_headers(),
732735
query_string_parameters={
@@ -738,13 +741,14 @@ def test_search_document_reference_invalid_json(repository: DocumentPointerRepos
738741
body = result.pop("body")
739742

740743
assert result == {
741-
"statusCode": "500",
744+
"statusCode": "200",
742745
"headers": default_response_headers(),
743746
"isBase64Encoded": False,
744747
}
745748

746749
parsed_body = json.loads(body)
747-
assert parsed_body == {
750+
751+
expected_operation_outcome = {
748752
"resourceType": "OperationOutcome",
749753
"issue": [
750754
{
@@ -763,3 +767,19 @@ def test_search_document_reference_invalid_json(repository: DocumentPointerRepos
763767
}
764768
],
765769
}
770+
771+
assert parsed_body == {
772+
"resourceType": "Bundle",
773+
"type": "searchset",
774+
"link": [
775+
{
776+
"relation": "self",
777+
"url": "https://pytest.api.service.nhs.uk/record-locator/consumer/FHIR/R4/DocumentReference?subject:identifier=https://fhir.nhs.uk/Id/nhs-number|6700028191",
778+
}
779+
],
780+
"total": 2,
781+
"entry": [
782+
{"resource": doc_ref.model_dump(exclude_none=True)},
783+
{"resource": expected_operation_outcome},
784+
],
785+
}

api/consumer/searchPostDocumentReference/search_post_document_reference.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
from nrlf.core.config import Config
66
from nrlf.core.decorators import request_handler
77
from nrlf.core.dynamodb.repository import DocumentPointerRepository
8-
from nrlf.core.errors import OperationOutcomeError
98
from nrlf.core.logger import LogReference, logger
109
from nrlf.core.model import ConnectionMetadata, ConsumerRequestParams
1110
from nrlf.core.response import Response, SpineErrorResponse
1211
from nrlf.core.validators import validate_category, validate_type
12+
from nrlf.producer.fhir.r4.model import OperationOutcome, OperationOutcomeIssue
1313

1414

1515
@request_handler(body=ConsumerRequestParams)
@@ -124,13 +124,21 @@ def handler(
124124
logger.log(
125125
LogReference.CONPOSTSEARCH005, error=str(exc), document=result.document
126126
)
127-
raise OperationOutcomeError(
128-
status_code="500",
129-
severity="error",
130-
code="exception",
131-
details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"),
132-
diagnostics="An error occurred whilst parsing the document reference search results",
133-
) from exc
127+
operation_outcome = OperationOutcome(
128+
resourceType="OperationOutcome",
129+
issue=[
130+
OperationOutcomeIssue(
131+
severity="error",
132+
code="exception",
133+
details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"),
134+
diagnostics="An error occurred whilst parsing the document reference search results",
135+
)
136+
],
137+
)
138+
bundle["total"] += 1
139+
bundle["entry"].append(
140+
{"resource": operation_outcome.model_dump(exclude_none=True)}
141+
)
134142

135143
response = Response.from_resource(Bundle.model_validate(bundle))
136144
logger.log(LogReference.CONPOSTSEARCH999)

api/consumer/searchPostDocumentReference/tests/test_search_post_document_reference_consumer.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -480,33 +480,39 @@ def test_search_document_reference_invalid_category(
480480

481481
@mock_aws
482482
@mock_repository
483-
def test_search_post_document_reference_invalid_json(
483+
def test_search_post_document_reference_invalid_json_adds_operation_outcome(
484484
repository: DocumentPointerRepository,
485485
):
486486
doc_ref = load_document_reference("Y05868-736253002-Valid")
487487
doc_pointer = DocumentPointer.from_document_reference(doc_ref)
488-
doc_pointer.document = "invalid json"
489-
490488
repository.create(doc_pointer)
491489

490+
doc_pointer_invalid = DocumentPointer.from_document_reference(doc_ref)
491+
doc_pointer_invalid.id = "Y05868-11111-99999-999992"
492+
doc_pointer_invalid.document = "invalid json"
493+
494+
repository.create(doc_pointer_invalid)
492495
event = create_test_api_gateway_event(
493496
headers=create_headers(),
494497
body=json.dumps(
495-
{"subject:identifier": "https://fhir.nhs.uk/Id/nhs-number|6700028191"}
498+
{
499+
"subject:identifier": "https://fhir.nhs.uk/Id/nhs-number|6700028191",
500+
}
496501
),
497502
)
498503

499504
result = handler(event, create_mock_context())
500505
body = result.pop("body")
501506

502507
assert result == {
503-
"statusCode": "500",
508+
"statusCode": "200",
504509
"headers": default_response_headers(),
505510
"isBase64Encoded": False,
506511
}
507512

508513
parsed_body = json.loads(body)
509-
assert parsed_body == {
514+
515+
expected_operation_outcome = {
510516
"resourceType": "OperationOutcome",
511517
"issue": [
512518
{
@@ -525,3 +531,19 @@ def test_search_post_document_reference_invalid_json(
525531
}
526532
],
527533
}
534+
535+
assert parsed_body == {
536+
"resourceType": "Bundle",
537+
"type": "searchset",
538+
"link": [
539+
{
540+
"relation": "self",
541+
"url": "https://pytest.api.service.nhs.uk/record-locator/consumer/FHIR/R4/DocumentReference?subject:identifier=https://fhir.nhs.uk/Id/nhs-number|6700028191",
542+
}
543+
],
544+
"total": 2,
545+
"entry": [
546+
{"resource": doc_ref.model_dump(exclude_none=True)},
547+
{"resource": expected_operation_outcome},
548+
],
549+
}

api/consumer/swagger.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -911,16 +911,18 @@ components:
911911
fullUrl:
912912
type: string
913913
pattern: \S*
914-
description: "The Absolute URL for the resource. The fullUrl SHALL NOT disagree with the id in the resource – i.e. if the fullUrl is not a urn:uuid, the URL shall be version–independent URL consistent with the Resource.id. The fullUrl is a version independent reference to the resource. The fullUrl element SHALL have a value except that: \n* fullUrl can be empty on a POST (although it does not need to when specifying a temporary id for reference in the bundle)\n* Results from operations might involve resources that are not identified."
914+
description: "The Absolute URL for the resource. The fullUrl SHALL NOT disagree with the id in the resource – i.e. if the fullUrl is not a urn:uuid, the URL shall be version–independent URL consistent with the Resource.id. The fullUrl is a version independent reference to the resource. The fullUrl element SHALL have a value except that: \n* fullUrl can be empty on a POST (although it does not need to when specifying a temporary id for reference in the bundle)\n* Results from operations might involve resources that are not identified."
915915
resource:
916-
$ref: "#/components/schemas/DocumentReference"
916+
oneOf:
917+
- $ref: "#/components/schemas/DocumentReference"
918+
- $ref: "#/components/schemas/OperationOutcome"
917919
description: The Resource for the entry. The purpose/meaning of the resource is determined by the Bundle.type.
918920
search:
919921
$ref: "#/components/schemas/BundleEntrySearch"
920922
description: Information about the search process that lead to the creation of this entry.
921923
request:
922924
$ref: "#/components/schemas/BundleEntryRequest"
923-
description: Additional information about how this entry should be processed as part of a transaction or batch. For history, it shows how the entry was processed to create the version contained in the entry.
925+
description: Additional information about how this entry should be processed as part of a transaction or batch. For history, it shows how the entry was processed to create the version contained in the entry.
924926
response:
925927
$ref: "#/components/schemas/BundleEntryResponse"
926928
description: Indicates the results of processing the corresponding 'request' entry in the batch or transaction being responded to or what the results of an operation where when returning history.

api/producer/searchDocumentReference/search_document_reference.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
from nrlf.core.codes import SpineErrorConcept
44
from nrlf.core.decorators import DocumentPointerRepository, request_handler
5-
from nrlf.core.errors import OperationOutcomeError
65
from nrlf.core.logger import LogReference, logger
76
from nrlf.core.model import ConnectionMetadata, ProducerRequestParams
87
from nrlf.core.response import Response, SpineErrorResponse
98
from nrlf.core.validators import validate_category, validate_type
10-
from nrlf.producer.fhir.r4.model import Bundle, DocumentReference
9+
from nrlf.producer.fhir.r4.model import (
10+
Bundle,
11+
DocumentReference,
12+
OperationOutcome,
13+
OperationOutcomeIssue,
14+
)
1115

1216

1317
@request_handler(params=ProducerRequestParams)
@@ -105,12 +109,20 @@ def handler(
105109
logger.log(
106110
LogReference.PROSEARCH005, error=str(exc), document=result.document
107111
)
108-
raise OperationOutcomeError(
109-
status_code="500",
110-
severity="error",
111-
code="exception",
112-
details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"),
113-
diagnostics="An error occurred whilst parsing the document reference search results",
112+
operation_outcome = OperationOutcome(
113+
resourceType="OperationOutcome",
114+
issue=[
115+
OperationOutcomeIssue(
116+
severity="error",
117+
code="exception",
118+
details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"),
119+
diagnostics="An error occurred whilst parsing the document reference search results",
120+
)
121+
],
122+
)
123+
bundle["total"] += 1
124+
bundle["entry"].append(
125+
{"resource": operation_outcome.model_dump(exclude_none=True)}
114126
)
115127

116128
response = Response.from_resource(Bundle.model_validate(bundle))

api/producer/searchDocumentReference/tests/test_search_document_reference_producer.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -460,10 +460,13 @@ def test_search_document_reference_filters_by_pointer_types(
460460
def test_search_document_reference_invalid_json(repository: DocumentPointerRepository):
461461
doc_ref = load_document_reference("Y05868-736253002-Valid")
462462
doc_pointer = DocumentPointer.from_document_reference(doc_ref)
463-
doc_pointer.document = "invalid json"
464-
465463
repository.create(doc_pointer)
466464

465+
doc_pointer_invalid = DocumentPointer.from_document_reference(doc_ref)
466+
doc_pointer_invalid.id = "Y05868-11111-99999-999992"
467+
doc_pointer_invalid.document = "invalid json"
468+
469+
repository.create(doc_pointer_invalid)
467470
event = create_test_api_gateway_event(
468471
headers=create_headers(),
469472
query_string_parameters={
@@ -475,13 +478,14 @@ def test_search_document_reference_invalid_json(repository: DocumentPointerRepos
475478
body = result.pop("body")
476479

477480
assert result == {
478-
"statusCode": "500",
481+
"statusCode": "200",
479482
"headers": default_response_headers(),
480483
"isBase64Encoded": False,
481484
}
482485

483486
parsed_body = json.loads(body)
484-
assert parsed_body == {
487+
488+
expected_operation_outcome = {
485489
"resourceType": "OperationOutcome",
486490
"issue": [
487491
{
@@ -500,3 +504,13 @@ def test_search_document_reference_invalid_json(repository: DocumentPointerRepos
500504
}
501505
],
502506
}
507+
508+
assert parsed_body == {
509+
"resourceType": "Bundle",
510+
"type": "searchset",
511+
"total": 2,
512+
"entry": [
513+
{"resource": doc_ref.model_dump(exclude_none=True)},
514+
{"resource": expected_operation_outcome},
515+
],
516+
}

api/producer/searchPostDocumentReference/search_post_document_reference.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
from nrlf.core.codes import SpineErrorConcept
44
from nrlf.core.decorators import DocumentPointerRepository, request_handler
5-
from nrlf.core.errors import OperationOutcomeError
65
from nrlf.core.logger import LogReference, logger
76
from nrlf.core.model import ConnectionMetadata, ProducerRequestParams
87
from nrlf.core.response import Response, SpineErrorResponse
98
from nrlf.core.validators import validate_category, validate_type
10-
from nrlf.producer.fhir.r4.model import Bundle, DocumentReference
9+
from nrlf.producer.fhir.r4.model import (
10+
Bundle,
11+
DocumentReference,
12+
OperationOutcome,
13+
OperationOutcomeIssue,
14+
)
1115

1216

1317
@request_handler(body=ProducerRequestParams)
@@ -99,12 +103,20 @@ def handler(
99103
logger.log(
100104
LogReference.PROPOSTSEARCH005, error=str(exc), document=result.document
101105
)
102-
raise OperationOutcomeError(
103-
status_code="500",
104-
severity="error",
105-
code="exception",
106-
details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"),
107-
diagnostics="An error occurred whilst parsing the document reference search results",
106+
operation_outcome = OperationOutcome(
107+
resourceType="OperationOutcome",
108+
issue=[
109+
OperationOutcomeIssue(
110+
severity="error",
111+
code="exception",
112+
details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"),
113+
diagnostics="An error occurred whilst parsing the document reference search results",
114+
)
115+
],
116+
)
117+
bundle["total"] += 1
118+
bundle["entry"].append(
119+
{"resource": operation_outcome.model_dump(exclude_none=True)}
108120
)
109121

110122
logger.log(LogReference.PROPOSTSEARCH999)

0 commit comments

Comments
 (0)