From 3d4594f2f03aa81ebe29c0368a0dc3934fcbe9db Mon Sep 17 00:00:00 2001 From: eesa456 Date: Thu, 1 May 2025 02:43:44 +0100 Subject: [PATCH 1/2] NRL-1418 return an operation outcome issue in the search bundle if a pointer is invalid in the search --- .../search_document_reference.py | 30 +++++++++++----- ...test_search_document_reference_consumer.py | 28 ++++++++++++--- .../search_post_document_reference.py | 24 ++++++++----- ...search_post_document_reference_consumer.py | 34 +++++++++++++++---- api/consumer/swagger.yaml | 8 +++-- .../search_document_reference.py | 28 ++++++++++----- ...test_search_document_reference_producer.py | 22 +++++++++--- .../search_post_document_reference.py | 28 ++++++++++----- ...search_post_document_reference_producer.py | 28 +++++++++++---- api/producer/swagger.yaml | 8 +++-- layer/nrlf/consumer/fhir/r4/model.py | 10 +++--- layer/nrlf/producer/fhir/r4/model.py | 10 +++--- layer/nrlf/producer/fhir/r4/strict_model.py | 10 +++--- 13 files changed, 194 insertions(+), 74 deletions(-) diff --git a/api/consumer/searchDocumentReference/search_document_reference.py b/api/consumer/searchDocumentReference/search_document_reference.py index d847e9ef4..7bc41d436 100644 --- a/api/consumer/searchDocumentReference/search_document_reference.py +++ b/api/consumer/searchDocumentReference/search_document_reference.py @@ -1,11 +1,15 @@ from pydantic import ValidationError -from nrlf.consumer.fhir.r4.model import Bundle, DocumentReference +from nrlf.consumer.fhir.r4.model import ( + Bundle, + DocumentReference, + OperationOutcome, + OperationOutcomeIssue, +) from nrlf.core.codes import SpineErrorConcept from nrlf.core.config import Config from nrlf.core.decorators import request_handler from nrlf.core.dynamodb.repository import DocumentPointerRepository -from nrlf.core.errors import OperationOutcomeError from nrlf.core.logger import LogReference, logger from nrlf.core.model import ConnectionMetadata, ConsumerRequestParams from nrlf.core.response import Response, SpineErrorResponse @@ -120,13 +124,21 @@ def handler( logger.log( LogReference.CONSEARCH005, error=str(exc), document=result.document ) - raise OperationOutcomeError( - status_code="500", - severity="error", - code="exception", - details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), - diagnostics="An error occurred whilst parsing the document reference search results", - ) from exc + operation_outcome = OperationOutcome( + resourceType="OperationOutcome", + issue=[ + OperationOutcomeIssue( + severity="error", + code="exception", + details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), + diagnostics=f"An error occurred whilst parsing the document reference search results", + ) + ], + ) + bundle["total"] += 1 + bundle["entry"].append( + {"resource": operation_outcome.model_dump(exclude_none=True)} + ) response = Response.from_resource(Bundle.model_validate(bundle)) logger.log(LogReference.CONSEARCH999) diff --git a/api/consumer/searchDocumentReference/tests/test_search_document_reference_consumer.py b/api/consumer/searchDocumentReference/tests/test_search_document_reference_consumer.py index 9643dad18..d4644a65b 100644 --- a/api/consumer/searchDocumentReference/tests/test_search_document_reference_consumer.py +++ b/api/consumer/searchDocumentReference/tests/test_search_document_reference_consumer.py @@ -561,10 +561,13 @@ def test_search_document_reference_invalid_category( def test_search_document_reference_invalid_json(repository: DocumentPointerRepository): doc_ref = load_document_reference("Y05868-736253002-Valid") doc_pointer = DocumentPointer.from_document_reference(doc_ref) - doc_pointer.document = "invalid json" - repository.create(doc_pointer) + doc_pointer_invalid = DocumentPointer.from_document_reference(doc_ref) + doc_pointer_invalid.id = "Y05868-11111-99999-999992" + doc_pointer_invalid.document = "invalid json" + + repository.create(doc_pointer_invalid) event = create_test_api_gateway_event( headers=create_headers(), query_string_parameters={ @@ -576,13 +579,14 @@ def test_search_document_reference_invalid_json(repository: DocumentPointerRepos body = result.pop("body") assert result == { - "statusCode": "500", + "statusCode": "200", "headers": default_response_headers(), "isBase64Encoded": False, } parsed_body = json.loads(body) - assert parsed_body == { + + expected_operation_outcome = { "resourceType": "OperationOutcome", "issue": [ { @@ -601,3 +605,19 @@ def test_search_document_reference_invalid_json(repository: DocumentPointerRepos } ], } + + assert parsed_body == { + "resourceType": "Bundle", + "type": "searchset", + "link": [ + { + "relation": "self", + "url": "https://pytest.api.service.nhs.uk/record-locator/consumer/FHIR/R4/DocumentReference?subject:identifier=https://fhir.nhs.uk/Id/nhs-number|6700028191", + } + ], + "total": 2, + "entry": [ + {"resource": doc_ref.model_dump(exclude_none=True)}, + {"resource": expected_operation_outcome}, + ], + } diff --git a/api/consumer/searchPostDocumentReference/search_post_document_reference.py b/api/consumer/searchPostDocumentReference/search_post_document_reference.py index 6cb9b7e8c..e0f0fd5d0 100644 --- a/api/consumer/searchPostDocumentReference/search_post_document_reference.py +++ b/api/consumer/searchPostDocumentReference/search_post_document_reference.py @@ -5,11 +5,11 @@ from nrlf.core.config import Config from nrlf.core.decorators import request_handler from nrlf.core.dynamodb.repository import DocumentPointerRepository -from nrlf.core.errors import OperationOutcomeError from nrlf.core.logger import LogReference, logger from nrlf.core.model import ConnectionMetadata, ConsumerRequestParams from nrlf.core.response import Response, SpineErrorResponse from nrlf.core.validators import validate_category, validate_type +from nrlf.producer.fhir.r4.model import OperationOutcome, OperationOutcomeIssue @request_handler(body=ConsumerRequestParams) @@ -124,13 +124,21 @@ def handler( logger.log( LogReference.CONPOSTSEARCH005, error=str(exc), document=result.document ) - raise OperationOutcomeError( - status_code="500", - severity="error", - code="exception", - details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), - diagnostics="An error occurred whilst parsing the document reference search results", - ) from exc + operation_outcome = OperationOutcome( + resourceType="OperationOutcome", + issue=[ + OperationOutcomeIssue( + severity="error", + code="exception", + details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), + diagnostics=f"An error occurred whilst parsing the document reference search results", + ) + ], + ) + bundle["total"] += 1 + bundle["entry"].append( + {"resource": operation_outcome.model_dump(exclude_none=True)} + ) response = Response.from_resource(Bundle.model_validate(bundle)) logger.log(LogReference.CONPOSTSEARCH999) diff --git a/api/consumer/searchPostDocumentReference/tests/test_search_post_document_reference_consumer.py b/api/consumer/searchPostDocumentReference/tests/test_search_post_document_reference_consumer.py index 6616ec51c..4a181fdc7 100644 --- a/api/consumer/searchPostDocumentReference/tests/test_search_post_document_reference_consumer.py +++ b/api/consumer/searchPostDocumentReference/tests/test_search_post_document_reference_consumer.py @@ -480,19 +480,24 @@ def test_search_document_reference_invalid_category( @mock_aws @mock_repository -def test_search_post_document_reference_invalid_json( +def test_search_post_document_reference_invalid_json_adds_operation_outcome( repository: DocumentPointerRepository, ): doc_ref = load_document_reference("Y05868-736253002-Valid") doc_pointer = DocumentPointer.from_document_reference(doc_ref) - doc_pointer.document = "invalid json" - repository.create(doc_pointer) + doc_pointer_invalid = DocumentPointer.from_document_reference(doc_ref) + doc_pointer_invalid.id = "Y05868-11111-99999-999992" + doc_pointer_invalid.document = "invalid json" + + repository.create(doc_pointer_invalid) event = create_test_api_gateway_event( headers=create_headers(), body=json.dumps( - {"subject:identifier": "https://fhir.nhs.uk/Id/nhs-number|6700028191"} + { + "subject:identifier": "https://fhir.nhs.uk/Id/nhs-number|6700028191", + } ), ) @@ -500,13 +505,14 @@ def test_search_post_document_reference_invalid_json( body = result.pop("body") assert result == { - "statusCode": "500", + "statusCode": "200", "headers": default_response_headers(), "isBase64Encoded": False, } parsed_body = json.loads(body) - assert parsed_body == { + + expected_operation_outcome = { "resourceType": "OperationOutcome", "issue": [ { @@ -525,3 +531,19 @@ def test_search_post_document_reference_invalid_json( } ], } + + assert parsed_body == { + "resourceType": "Bundle", + "type": "searchset", + "link": [ + { + "relation": "self", + "url": "https://pytest.api.service.nhs.uk/record-locator/consumer/FHIR/R4/DocumentReference?subject:identifier=https://fhir.nhs.uk/Id/nhs-number|6700028191", + } + ], + "total": 2, + "entry": [ + {"resource": doc_ref.model_dump(exclude_none=True)}, + {"resource": expected_operation_outcome}, + ], + } diff --git a/api/consumer/swagger.yaml b/api/consumer/swagger.yaml index 5d016c4e7..b37540e26 100644 --- a/api/consumer/swagger.yaml +++ b/api/consumer/swagger.yaml @@ -911,16 +911,18 @@ components: fullUrl: type: string pattern: \S* - 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." + 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." resource: - $ref: "#/components/schemas/DocumentReference" + oneOf: + - $ref: "#/components/schemas/DocumentReference" + - $ref: "#/components/schemas/OperationOutcome" description: The Resource for the entry. The purpose/meaning of the resource is determined by the Bundle.type. search: $ref: "#/components/schemas/BundleEntrySearch" description: Information about the search process that lead to the creation of this entry. request: $ref: "#/components/schemas/BundleEntryRequest" - 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. + 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. response: $ref: "#/components/schemas/BundleEntryResponse" 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. diff --git a/api/producer/searchDocumentReference/search_document_reference.py b/api/producer/searchDocumentReference/search_document_reference.py index e961e7b9f..791f38d91 100644 --- a/api/producer/searchDocumentReference/search_document_reference.py +++ b/api/producer/searchDocumentReference/search_document_reference.py @@ -2,12 +2,16 @@ from nrlf.core.codes import SpineErrorConcept from nrlf.core.decorators import DocumentPointerRepository, request_handler -from nrlf.core.errors import OperationOutcomeError from nrlf.core.logger import LogReference, logger from nrlf.core.model import ConnectionMetadata, ProducerRequestParams from nrlf.core.response import Response, SpineErrorResponse from nrlf.core.validators import validate_category, validate_type -from nrlf.producer.fhir.r4.model import Bundle, DocumentReference +from nrlf.producer.fhir.r4.model import ( + Bundle, + DocumentReference, + OperationOutcome, + OperationOutcomeIssue, +) @request_handler(params=ProducerRequestParams) @@ -105,12 +109,20 @@ def handler( logger.log( LogReference.PROSEARCH005, error=str(exc), document=result.document ) - raise OperationOutcomeError( - status_code="500", - severity="error", - code="exception", - details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), - diagnostics="An error occurred whilst parsing the document reference search results", + operation_outcome = OperationOutcome( + resourceType="OperationOutcome", + issue=[ + OperationOutcomeIssue( + severity="error", + code="exception", + details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), + diagnostics=f"An error occurred whilst parsing the document reference search results", + ) + ], + ) + bundle["total"] += 1 + bundle["entry"].append( + {"resource": operation_outcome.model_dump(exclude_none=True)} ) response = Response.from_resource(Bundle.model_validate(bundle)) diff --git a/api/producer/searchDocumentReference/tests/test_search_document_reference_producer.py b/api/producer/searchDocumentReference/tests/test_search_document_reference_producer.py index b577f7754..92de1ef8e 100644 --- a/api/producer/searchDocumentReference/tests/test_search_document_reference_producer.py +++ b/api/producer/searchDocumentReference/tests/test_search_document_reference_producer.py @@ -460,10 +460,13 @@ def test_search_document_reference_filters_by_pointer_types( def test_search_document_reference_invalid_json(repository: DocumentPointerRepository): doc_ref = load_document_reference("Y05868-736253002-Valid") doc_pointer = DocumentPointer.from_document_reference(doc_ref) - doc_pointer.document = "invalid json" - repository.create(doc_pointer) + doc_pointer_invalid = DocumentPointer.from_document_reference(doc_ref) + doc_pointer_invalid.id = "Y05868-11111-99999-999992" + doc_pointer_invalid.document = "invalid json" + + repository.create(doc_pointer_invalid) event = create_test_api_gateway_event( headers=create_headers(), query_string_parameters={ @@ -475,13 +478,14 @@ def test_search_document_reference_invalid_json(repository: DocumentPointerRepos body = result.pop("body") assert result == { - "statusCode": "500", + "statusCode": "200", "headers": default_response_headers(), "isBase64Encoded": False, } parsed_body = json.loads(body) - assert parsed_body == { + + expected_operation_outcome = { "resourceType": "OperationOutcome", "issue": [ { @@ -500,3 +504,13 @@ def test_search_document_reference_invalid_json(repository: DocumentPointerRepos } ], } + + assert parsed_body == { + "resourceType": "Bundle", + "type": "searchset", + "total": 2, + "entry": [ + {"resource": doc_ref.model_dump(exclude_none=True)}, + {"resource": expected_operation_outcome}, + ], + } diff --git a/api/producer/searchPostDocumentReference/search_post_document_reference.py b/api/producer/searchPostDocumentReference/search_post_document_reference.py index 023dcfe7c..ba932feb5 100644 --- a/api/producer/searchPostDocumentReference/search_post_document_reference.py +++ b/api/producer/searchPostDocumentReference/search_post_document_reference.py @@ -2,12 +2,16 @@ from nrlf.core.codes import SpineErrorConcept from nrlf.core.decorators import DocumentPointerRepository, request_handler -from nrlf.core.errors import OperationOutcomeError from nrlf.core.logger import LogReference, logger from nrlf.core.model import ConnectionMetadata, ProducerRequestParams from nrlf.core.response import Response, SpineErrorResponse from nrlf.core.validators import validate_category, validate_type -from nrlf.producer.fhir.r4.model import Bundle, DocumentReference +from nrlf.producer.fhir.r4.model import ( + Bundle, + DocumentReference, + OperationOutcome, + OperationOutcomeIssue, +) @request_handler(body=ProducerRequestParams) @@ -99,12 +103,20 @@ def handler( logger.log( LogReference.PROPOSTSEARCH005, error=str(exc), document=result.document ) - raise OperationOutcomeError( - status_code="500", - severity="error", - code="exception", - details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), - diagnostics="An error occurred whilst parsing the document reference search results", + operation_outcome = OperationOutcome( + resourceType="OperationOutcome", + issue=[ + OperationOutcomeIssue( + severity="error", + code="exception", + details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), + diagnostics=f"An error occurred whilst parsing the document reference search results", + ) + ], + ) + bundle["total"] += 1 + bundle["entry"].append( + {"resource": operation_outcome.model_dump(exclude_none=True)} ) logger.log(LogReference.PROPOSTSEARCH999) diff --git a/api/producer/searchPostDocumentReference/tests/test_search_post_document_reference_producer.py b/api/producer/searchPostDocumentReference/tests/test_search_post_document_reference_producer.py index 8340ee0d3..c95a6dba6 100644 --- a/api/producer/searchPostDocumentReference/tests/test_search_post_document_reference_producer.py +++ b/api/producer/searchPostDocumentReference/tests/test_search_post_document_reference_producer.py @@ -474,19 +474,24 @@ def test_search_document_reference_filters_by_pointer_types( @mock_aws @mock_repository -def test_search_post_document_reference_invalid_json( +def test_search_post_document_reference_invalid_json_adds_operation_outcome( repository: DocumentPointerRepository, ): doc_ref = load_document_reference("Y05868-736253002-Valid") doc_pointer = DocumentPointer.from_document_reference(doc_ref) - doc_pointer.document = "invalid json" - repository.create(doc_pointer) + doc_pointer_invalid = DocumentPointer.from_document_reference(doc_ref) + doc_pointer_invalid.id = "Y05868-11111-99999-999992" + doc_pointer_invalid.document = "invalid json" + + repository.create(doc_pointer_invalid) event = create_test_api_gateway_event( headers=create_headers(), body=json.dumps( - {"subject:identifier": "https://fhir.nhs.uk/Id/nhs-number|6700028191"} + { + "subject:identifier": "https://fhir.nhs.uk/Id/nhs-number|6700028191", + } ), ) @@ -494,13 +499,14 @@ def test_search_post_document_reference_invalid_json( body = result.pop("body") assert result == { - "statusCode": "500", + "statusCode": "200", "headers": default_response_headers(), "isBase64Encoded": False, } parsed_body = json.loads(body) - assert parsed_body == { + + expected_operation_outcome = { "resourceType": "OperationOutcome", "issue": [ { @@ -519,3 +525,13 @@ def test_search_post_document_reference_invalid_json( } ], } + + assert parsed_body == { + "resourceType": "Bundle", + "type": "searchset", + "total": 2, + "entry": [ + {"resource": doc_ref.model_dump(exclude_none=True)}, + {"resource": expected_operation_outcome}, + ], + } diff --git a/api/producer/swagger.yaml b/api/producer/swagger.yaml index 76d1f4284..3d44a8f7e 100644 --- a/api/producer/swagger.yaml +++ b/api/producer/swagger.yaml @@ -1478,16 +1478,18 @@ components: fullUrl: type: string pattern: \S* - 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." + 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." resource: - $ref: "#/components/schemas/DocumentReference" + oneOf: + - $ref: "#/components/schemas/DocumentReference" + - $ref: "#/components/schemas/OperationOutcome" description: The Resource for the entry. The purpose/meaning of the resource is determined by the Bundle.type. search: $ref: "#/components/schemas/BundleEntrySearch" description: Information about the search process that lead to the creation of this entry. request: $ref: "#/components/schemas/BundleEntryRequest" - 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. + 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. response: $ref: "#/components/schemas/BundleEntryResponse" 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. diff --git a/layer/nrlf/consumer/fhir/r4/model.py b/layer/nrlf/consumer/fhir/r4/model.py index 5f9b911a6..41f9d4f66 100644 --- a/layer/nrlf/consumer/fhir/r4/model.py +++ b/layer/nrlf/consumer/fhir/r4/model.py @@ -1,10 +1,10 @@ # generated by datamodel-codegen: # filename: swagger.yaml -# timestamp: 2025-02-07T14:10:39+00:00 +# timestamp: 2025-05-01T01:11:14+00:00 from __future__ import annotations -from typing import Annotated, List, Literal, Optional +from typing import Annotated, List, Literal, Optional, Union from pydantic import Field, RootModel @@ -800,12 +800,12 @@ class BundleEntry(Parent): fullUrl: Annotated[ Optional[str], Field( - 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.", + 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.", pattern="\\S*", ), ] = None resource: Annotated[ - Optional[DocumentReference], + Optional[Union[DocumentReference, OperationOutcome]], Field( description="The Resource for the entry. The purpose/meaning of the resource is determined by the Bundle.type." ), @@ -819,7 +819,7 @@ class BundleEntry(Parent): request: Annotated[ Optional[BundleEntryRequest], Field( - 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." + 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." ), ] = None response: Annotated[ diff --git a/layer/nrlf/producer/fhir/r4/model.py b/layer/nrlf/producer/fhir/r4/model.py index 715a7e12e..8731e4c9a 100644 --- a/layer/nrlf/producer/fhir/r4/model.py +++ b/layer/nrlf/producer/fhir/r4/model.py @@ -1,10 +1,10 @@ # generated by datamodel-codegen: # filename: swagger.yaml -# timestamp: 2025-02-07T14:10:35+00:00 +# timestamp: 2025-05-01T01:11:10+00:00 from __future__ import annotations -from typing import Annotated, List, Literal, Optional +from typing import Annotated, List, Literal, Optional, Union from pydantic import ConfigDict, Field, RootModel @@ -846,12 +846,12 @@ class BundleEntry(Parent): fullUrl: Annotated[ Optional[str], Field( - 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.", + 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.", pattern="\\S*", ), ] = None resource: Annotated[ - Optional[DocumentReference], + Optional[Union[DocumentReference, OperationOutcome]], Field( description="The Resource for the entry. The purpose/meaning of the resource is determined by the Bundle.type." ), @@ -865,7 +865,7 @@ class BundleEntry(Parent): request: Annotated[ Optional[BundleEntryRequest], Field( - 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." + 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." ), ] = None response: Annotated[ diff --git a/layer/nrlf/producer/fhir/r4/strict_model.py b/layer/nrlf/producer/fhir/r4/strict_model.py index d7849f154..631f28447 100644 --- a/layer/nrlf/producer/fhir/r4/strict_model.py +++ b/layer/nrlf/producer/fhir/r4/strict_model.py @@ -1,10 +1,10 @@ # generated by datamodel-codegen: # filename: swagger.yaml -# timestamp: 2025-02-07T14:10:37+00:00 +# timestamp: 2025-05-01T01:11:12+00:00 from __future__ import annotations -from typing import Annotated, List, Literal, Optional +from typing import Annotated, List, Literal, Optional, Union from pydantic import ( ConfigDict, @@ -749,11 +749,11 @@ class BundleEntry(Parent): fullUrl: Annotated[ Optional[StrictStr], Field( - 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." + 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." ), ] = None resource: Annotated[ - Optional[DocumentReference], + Optional[Union[DocumentReference, OperationOutcome]], Field( description="The Resource for the entry. The purpose/meaning of the resource is determined by the Bundle.type." ), @@ -767,7 +767,7 @@ class BundleEntry(Parent): request: Annotated[ Optional[BundleEntryRequest], Field( - 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." + 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." ), ] = None response: Annotated[ From e60e059f7612fe89aa6d4dafde2541ea5e863d3f Mon Sep 17 00:00:00 2001 From: eesa456 Date: Thu, 1 May 2025 03:08:39 +0100 Subject: [PATCH 2/2] NRL-1418 remove f string --- .../searchDocumentReference/search_document_reference.py | 2 +- .../search_post_document_reference.py | 2 +- .../searchDocumentReference/search_document_reference.py | 2 +- .../search_post_document_reference.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/consumer/searchDocumentReference/search_document_reference.py b/api/consumer/searchDocumentReference/search_document_reference.py index 7bc41d436..c5c211aa1 100644 --- a/api/consumer/searchDocumentReference/search_document_reference.py +++ b/api/consumer/searchDocumentReference/search_document_reference.py @@ -131,7 +131,7 @@ def handler( severity="error", code="exception", details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), - diagnostics=f"An error occurred whilst parsing the document reference search results", + diagnostics="An error occurred whilst parsing the document reference search results", ) ], ) diff --git a/api/consumer/searchPostDocumentReference/search_post_document_reference.py b/api/consumer/searchPostDocumentReference/search_post_document_reference.py index e0f0fd5d0..4dc3ca4e3 100644 --- a/api/consumer/searchPostDocumentReference/search_post_document_reference.py +++ b/api/consumer/searchPostDocumentReference/search_post_document_reference.py @@ -131,7 +131,7 @@ def handler( severity="error", code="exception", details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), - diagnostics=f"An error occurred whilst parsing the document reference search results", + diagnostics="An error occurred whilst parsing the document reference search results", ) ], ) diff --git a/api/producer/searchDocumentReference/search_document_reference.py b/api/producer/searchDocumentReference/search_document_reference.py index 791f38d91..190e2d93a 100644 --- a/api/producer/searchDocumentReference/search_document_reference.py +++ b/api/producer/searchDocumentReference/search_document_reference.py @@ -116,7 +116,7 @@ def handler( severity="error", code="exception", details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), - diagnostics=f"An error occurred whilst parsing the document reference search results", + diagnostics="An error occurred whilst parsing the document reference search results", ) ], ) diff --git a/api/producer/searchPostDocumentReference/search_post_document_reference.py b/api/producer/searchPostDocumentReference/search_post_document_reference.py index ba932feb5..45324c018 100644 --- a/api/producer/searchPostDocumentReference/search_post_document_reference.py +++ b/api/producer/searchPostDocumentReference/search_post_document_reference.py @@ -110,7 +110,7 @@ def handler( severity="error", code="exception", details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), - diagnostics=f"An error occurred whilst parsing the document reference search results", + diagnostics="An error occurred whilst parsing the document reference search results", ) ], )