Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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="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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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={
Expand All @@ -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": [
{
Expand All @@ -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},
],
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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="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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -480,33 +480,39 @@ 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",
}
),
)

result = handler(event, create_mock_context())
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": [
{
Expand All @@ -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},
],
}
8 changes: 5 additions & 3 deletions api/consumer/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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="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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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={
Expand All @@ -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": [
{
Expand All @@ -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},
],
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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="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)
Expand Down
Loading
Loading