Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
4ed5144
NRL-1554 Add new content retrieval mechanism extension
eesa456 Aug 7, 2025
9fd7818
NRL-1554 sonar qube fixes
eesa456 Aug 11, 2025
a523b94
NRL-1554 reduce complexity
eesa456 Aug 11, 2025
2790ae2
NRL-1554 add retrieval mechanism extension to int tests
eesa456 Aug 11, 2025
aac33c0
NRL-1554 Fix missing swagger changes from NRL-1472
axelkrastek1-nhs Aug 18, 2025
9381198
NRL-1554 Allow arbitrary extensions in content, change diagnostic mes…
axelkrastek1-nhs Aug 18, 2025
8a3b82f
NRL-1554 Remove previous modifications to unit tests
axelkrastek1-nhs Aug 18, 2025
a25467b
NRL-1554 Remove commented code
axelkrastek1-nhs Aug 19, 2025
c7f89c8
NRL-1554 Add test for two retrieval mechanisms
axelkrastek1-nhs Aug 19, 2025
d945e98
NRL-1554 Lowercase matching for extensions, remove unused code, add r…
axelkrastek1-nhs Aug 26, 2025
e4ad92d
NRL-1554 Replace NDR for LDR (Large Document Repository)
axelkrastek1-nhs Aug 27, 2025
0be0f57
NRL-1554 Remove check for empty content extension as it is checked in…
axelkrastek1-nhs Aug 27, 2025
daf09f0
NRL-1554 Add more negative test scenarios
axelkrastek1-nhs Aug 27, 2025
f40b44f
NRL-1554 Bump fhir resources versions and fix sonarcloud warning
axelkrastek1-nhs Aug 27, 2025
0b32adc
NRL-1554 Add test for two contents with different retrieval mechanisms
axelkrastek1-nhs Aug 27, 2025
7357fdf
NRL-1554 Change order of display to match the code
axelkrastek1-nhs Aug 28, 2025
6fa21a6
NRL-1554 Reduce cognitive complexity
axelkrastek1-nhs Aug 28, 2025
e444ccc
NRL-1554 Fix integration test
axelkrastek1-nhs Sep 2, 2025
0e81e6a
NRL-1554 Retrieval instead of Repository, add unit tests
axelkrastek1-nhs Sep 5, 2025
1ffa66a
NRL-1554 Fix unit test
axelkrastek1-nhs Sep 5, 2025
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
56 changes: 53 additions & 3 deletions api/consumer/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -810,10 +810,12 @@ components:
extension:
type: array
items:
$ref: "#/components/schemas/ContentStabilityExtension"
description: Additional extension for content stability.
oneOf:
- $ref: "#/components/schemas/ContentStabilityExtension"
- $ref: "#/components/schemas/RetrievalMechanismExtension"
- $ref: "#/components/schemas/Extension"
description: Additional extensions which include Content Stability and Retrieval Mechanism.
minItems: 1
maxItems: 1
required:
- attachment
- format
Expand Down Expand Up @@ -975,6 +977,52 @@ components:
- system
- code
- display
RetrievalMechanismExtension:
allOf:
- $ref: "#/components/schemas/Extension"
- type: object
properties:
url:
type: string
enum:
- "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-RetrievalMechanism"
valueCodeableConcept:
$ref: "#/components/schemas/RetrievalMechanismExtensionValueCodeableConcept"
required:
- url
- valueCodeableConcept
RetrievalMechanismExtensionValueCodeableConcept:
allOf:
- $ref: "#/components/schemas/CodeableConcept"
- type: object
properties:
coding:
type: array
items:
$ref: "#/components/schemas/RetrievalMechanismExtensionCoding"
minItems: 1
maxItems: 1
required:
- coding
RetrievalMechanismExtensionCoding:
allOf:
- $ref: "#/components/schemas/Coding"
- type: object
properties:
system:
type: string
enum:
- "https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism"
code:
type: string
enum: ["SSP", "Direct", "LDR"]
display:
type: string
enum: ["Spine Secure Proxy", "Direct", "Large Document Retrieval"]
required:
- system
- code
- display
NRLFormatCode:
allOf:
- $ref: "#/components/schemas/Coding"
Expand All @@ -990,12 +1038,14 @@ components:
enum:
- "urn:nhs-ic:record-contact"
- "urn:nhs-ic:unstructured"
- "urn:nhs-ic:structured"
description: The code representing the format of the document.
display:
type: string
enum:
- "Contact details (HTTP Unsecured)"
- "Unstructured Document"
- "Structured Document"
description: The display text for the code.
required:
- system
Expand Down
56 changes: 53 additions & 3 deletions api/producer/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1415,10 +1415,12 @@ components:
extension:
type: array
items:
$ref: "#/components/schemas/ContentStabilityExtension"
description: Additional extension for content stability.
oneOf:
- $ref: "#/components/schemas/ContentStabilityExtension"
- $ref: "#/components/schemas/RetrievalMechanismExtension"
- $ref: "#/components/schemas/Extension"
description: Additional extensions which include Content Stability and Retrieval Mechanism.
minItems: 1
maxItems: 1
required:
- attachment
- format
Expand Down Expand Up @@ -1631,6 +1633,52 @@ components:
- system
- code
- display
RetrievalMechanismExtension:
allOf:
- $ref: "#/components/schemas/Extension"
- type: object
properties:
url:
type: string
enum:
- "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-RetrievalMechanism"
valueCodeableConcept:
$ref: "#/components/schemas/RetrievalMechanismExtensionValueCodeableConcept"
required:
- url
- valueCodeableConcept
RetrievalMechanismExtensionValueCodeableConcept:
allOf:
- $ref: "#/components/schemas/CodeableConcept"
- type: object
properties:
coding:
type: array
items:
$ref: "#/components/schemas/RetrievalMechanismExtensionCoding"
minItems: 1
maxItems: 1
required:
- coding
RetrievalMechanismExtensionCoding:
allOf:
- $ref: "#/components/schemas/Coding"
- type: object
properties:
system:
type: string
enum:
- "https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism"
code:
type: string
enum: ["SSP", "Direct", "LDR"]
display:
type: string
enum: ["Spine Secure Proxy", "Direct", "Large Document Retrieval"]
required:
- system
- code
- display
NRLFormatCode:
allOf:
- $ref: "#/components/schemas/Coding"
Expand All @@ -1646,12 +1694,14 @@ components:
enum:
- "urn:nhs-ic:record-contact"
- "urn:nhs-ic:unstructured"
- "urn:nhs-ic:structured"
description: The code representing the format of the document.
display:
type: string
enum:
- "Contact details (HTTP Unsecured)"
- "Unstructured Document"
- "Structured Document"
description: The display text for the code.
required:
- system
Expand Down
24 changes: 22 additions & 2 deletions layer/nrlf/consumer/fhir/r4/model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# generated by datamodel-codegen:
# filename: swagger.yaml
# timestamp: 2025-06-13T14:43:32+00:00
# timestamp: 2025-09-05T08:22:10+00:00

from __future__ import annotations

Expand Down Expand Up @@ -240,6 +240,12 @@ class ContentStabilityExtensionCoding(Coding):
display: Literal["Static", "Dynamic"]


class RetrievalMechanismExtensionCoding(Coding):
system: Literal["https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism"]
code: Literal["SSP", "Direct", "LDR"]
display: Literal["Spine Secure Proxy", "Direct", "Large Document Retrieval"]


class NRLFormatCode(Coding):
system: Annotated[
Literal["https://fhir.nhs.uk/England/CodeSystem/England-NRLFormatCode"],
Expand Down Expand Up @@ -501,6 +507,12 @@ class ContentStabilityExtensionValueCodeableConcept(CodeableConcept):
]


class RetrievalMechanismExtensionValueCodeableConcept(CodeableConcept):
coding: Annotated[
List[RetrievalMechanismExtensionCoding], Field(max_length=1, min_length=1)
]


class RequestHeader(Parent):
odsCode: RequestHeaderOdsCode

Expand Down Expand Up @@ -574,6 +586,13 @@ class ContentStabilityExtension(Extension):
valueCodeableConcept: ContentStabilityExtensionValueCodeableConcept


class RetrievalMechanismExtension(Extension):
url: Literal[
"https://fhir.nhs.uk/England/StructureDefinition/Extension-England-RetrievalMechanism"
]
valueCodeableConcept: RetrievalMechanismExtensionValueCodeableConcept


class OperationOutcome(Parent):
resourceType: Literal["OperationOutcome"]
id: Annotated[
Expand Down Expand Up @@ -633,7 +652,8 @@ class DocumentReferenceContent(Parent):
),
]
extension: Annotated[
List[ContentStabilityExtension], Field(max_length=1, min_length=1)
List[Union[ContentStabilityExtension, RetrievalMechanismExtension, Extension]],
Field(min_length=1),
]


Expand Down
9 changes: 9 additions & 0 deletions layer/nrlf/core/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,9 +677,18 @@ def coding_value(self):
CONTENT_STABILITY_EXTENSION_URL = (
"https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability"
)
CONTENT_RETRIEVAL_EXTENSION_URL = "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-RetrievalMechanism"
CONTENT_STABILITY_SYSTEM_URL = (
"https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability"
)
CONTENT_RETRIEVAL_SYSTEM_URL = (
"https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism"
)
CONTENT_RETRIEVAL_CODE_MAP = {
"Direct": "Direct",
"SSP": "Spine Secure Proxy",
"LDR": "Large Document Retrieval",
}
CONTENT_FORMAT_CODE_URL = "https://fhir.nhs.uk/England/CodeSystem/England-NRLFormatCode"
CONTENT_FORMAT_CODE_MAP = {
"urn:nhs-ic:record-contact": "Contact details (HTTP Unsecured)",
Expand Down
43 changes: 22 additions & 21 deletions layer/nrlf/core/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from pydantic import ValidationError
from pydantic_core import ErrorDetails

from nrlf.core.constants import CONTENT_FORMAT_CODE_URL, CONTENT_STABILITY_SYSTEM_URL
from nrlf.core.response import Response
from nrlf.core.types import CodeableConcept
from nrlf.producer.fhir.r4 import model as producer_model
Expand All @@ -20,28 +19,25 @@ def format_error_location(loc: List) -> str:
return formatted_loc


def append_value_set_url(loc_string: str) -> str:
if loc_string.endswith(("url", "system")):
return ""

if "content" in loc_string:
if "extension" in loc_string:
return f". See ValueSet: {CONTENT_STABILITY_SYSTEM_URL}"
if "format" in loc_string:
return f". See ValueSet: {CONTENT_FORMAT_CODE_URL}"

return ""


def diag_for_error(error: ErrorDetails) -> str:
def diag_for_error(error: ErrorDetails, value_set: str, root_location: tuple) -> str:
loc_string = format_error_location(error["loc"])
if root_location:
loc_string = format_error_location(root_location) + "." + loc_string

msg = f"{loc_string or 'DocumentReference'}: {error['msg']}"
msg += append_value_set_url(loc_string)
msg += f", see: {value_set}" if value_set else ""
return msg


def expression_for_error(error: ErrorDetails) -> Optional[str]:
return format_error_location(error["loc"]) or "DocumentReference"
def expression_for_error(error: ErrorDetails, root_location: tuple) -> Optional[str]:
loc_string = format_error_location(error["loc"]) or "DocumentReference"
if root_location and error["loc"]:
loc_string = (
format_error_location(root_location)
+ "."
+ format_error_location(error["loc"])
)
return loc_string


class OperationOutcomeError(Exception):
Expand Down Expand Up @@ -91,15 +87,20 @@ def __init__(self, issues: List[OperationOutcomeIssue]):

@classmethod
def from_validation_error(
cls, exc: ValidationError, details: CodeableConcept, msg: str = ""
cls,
exc: ValidationError,
details: CodeableConcept,
msg: str = "",
value_set: str = "",
root_location: tuple = None,
):
issues = [
producer_model.OperationOutcomeIssue(
severity="error",
code="invalid",
details=details, # type: ignore
diagnostics=f"{msg} ({diag_for_error(error)})",
expression=[expression_for_error(error)], # type: ignore
diagnostics=f"{msg} ({diag_for_error(error, value_set, root_location)})",
expression=[expression_for_error(error, root_location)], # type: ignore
)
for error in exc.errors()
]
Expand Down
Loading