-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathapi_error_response.py
More file actions
147 lines (124 loc) · 5.4 KB
/
api_error_response.py
File metadata and controls
147 lines (124 loc) · 5.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import json
import logging
import uuid
from datetime import UTC, datetime
from enum import Enum
from http import HTTPStatus
from typing import Any
from fhir.resources.operationoutcome import OperationOutcome, OperationOutcomeIssue
logger = logging.getLogger(__name__)
class FHIRIssueSeverity(str, Enum):
FATAL = "fatal"
ERROR = "error"
WARNING = "warning"
INFORMATION = "information"
class FHIRIssueCode(str, Enum):
FORBIDDEN = "forbidden"
PROCESSING = "processing"
VALUE = "value"
class FHIRSpineErrorCode(str, Enum):
INVALID_NHS_NUMBER = "INVALID_NHS_NUMBER"
INVALID_PARAMETER = "INVALID_PARAMETER"
INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"
REFERENCE_NOT_FOUND = "REFERENCE_NOT_FOUND"
class APIErrorResponse:
def __init__( # noqa: PLR0913
self,
status_code: HTTPStatus,
fhir_issue_code: FHIRIssueCode,
fhir_issue_severity: FHIRIssueSeverity,
fhir_coding_system: str,
fhir_error_code: str,
fhir_display_message: str,
) -> None:
self.status_code = status_code
self.fhir_issue_code = fhir_issue_code
self.fhir_issue_severity = fhir_issue_severity
self.fhir_coding_system = fhir_coding_system
self.fhir_error_code = fhir_error_code
self.fhir_display_message = fhir_display_message
def build_operation_outcome_issue(self, diagnostics: str, location: list[str] | None) -> OperationOutcomeIssue:
details = {
"coding": [
{
"system": self.fhir_coding_system,
"code": self.fhir_error_code,
"display": self.fhir_display_message,
}
]
}
return OperationOutcomeIssue(
severity=self.fhir_issue_severity,
code=self.fhir_issue_code,
diagnostics=diagnostics,
location=location,
details=details,
) # pyright: ignore[reportCallIssue]
def generate_response(self, diagnostics: str, location_param: str | None = None) -> dict[str, Any]:
issue_location = [f"parameters/{location_param}"] if location_param else None
problem = OperationOutcome(
id=str(uuid.uuid4()),
meta={"lastUpdated": datetime.now(UTC)},
issue=[self.build_operation_outcome_issue(diagnostics, issue_location)],
) # pyright: ignore[reportCallIssue]
response_body = json.dumps(problem.model_dump(by_alias=True, mode="json"))
return {
"statusCode": self.status_code,
"headers": {"Content-Type": "application/fhir+json"},
"body": response_body,
}
def log_and_generate_response(
self, log_message: str, diagnostics: str, location_param: str | None = None
) -> dict[str, Any]:
logger.error(log_message)
return self.generate_response(diagnostics, location_param)
INVALID_INCLUDE_ACTIONS_ERROR = APIErrorResponse(
status_code=HTTPStatus.UNPROCESSABLE_ENTITY,
fhir_issue_code=FHIRIssueCode.VALUE,
fhir_issue_severity=FHIRIssueSeverity.ERROR,
fhir_coding_system="https://fhir.nhs.uk/STU3/ValueSet/Spine-ErrorOrWarningCode-1",
fhir_error_code=FHIRSpineErrorCode.INVALID_PARAMETER,
fhir_display_message="The supplied value was not recognised by the API.",
)
INVALID_CATEGORY_ERROR = APIErrorResponse(
status_code=HTTPStatus.UNPROCESSABLE_ENTITY,
fhir_issue_code=FHIRIssueCode.VALUE,
fhir_issue_severity=FHIRIssueSeverity.ERROR,
fhir_coding_system="https://fhir.nhs.uk/STU3/ValueSet/Spine-ErrorOrWarningCode-1",
fhir_error_code=FHIRSpineErrorCode.INVALID_PARAMETER,
fhir_display_message="The supplied category was not recognised by the API.",
)
INVALID_CONDITION_FORMAT_ERROR = APIErrorResponse(
status_code=HTTPStatus.BAD_REQUEST,
fhir_issue_code=FHIRIssueCode.VALUE,
fhir_issue_severity=FHIRIssueSeverity.ERROR,
fhir_coding_system="https://fhir.nhs.uk/STU3/ValueSet/Spine-ErrorOrWarningCode-1",
fhir_error_code=FHIRSpineErrorCode.INVALID_PARAMETER,
fhir_display_message="The given conditions were not in the expected format.",
)
NHS_NUMBER_NOT_FOUND_ERROR = APIErrorResponse(
status_code=HTTPStatus.NOT_FOUND,
fhir_issue_code=FHIRIssueCode.PROCESSING,
fhir_issue_severity=FHIRIssueSeverity.ERROR,
fhir_coding_system="https://fhir.nhs.uk/STU3/ValueSet/Spine-ErrorOrWarningCode-1",
fhir_error_code=FHIRSpineErrorCode.REFERENCE_NOT_FOUND,
fhir_display_message="The given NHS number was not found in our datasets. "
"This could be because the number is incorrect or "
"some other reason we cannot process that number.",
)
INTERNAL_SERVER_ERROR = APIErrorResponse(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
fhir_issue_code=FHIRIssueCode.PROCESSING,
fhir_issue_severity=FHIRIssueSeverity.ERROR,
fhir_coding_system="https://fhir.nhs.uk/STU3/ValueSet/Spine-ErrorOrWarningCode-1",
fhir_error_code=FHIRSpineErrorCode.INTERNAL_SERVER_ERROR,
fhir_display_message="An unexpected internal server error occurred.",
)
NHS_NUMBER_MISMATCH_ERROR = APIErrorResponse(
status_code=HTTPStatus.FORBIDDEN,
fhir_issue_code=FHIRIssueCode.FORBIDDEN,
fhir_issue_severity=FHIRIssueSeverity.ERROR,
fhir_coding_system="https://fhir.nhs.uk/STU3/ValueSet/Spine-ErrorOrWarningCode-1",
fhir_error_code=FHIRSpineErrorCode.INVALID_NHS_NUMBER,
fhir_display_message="The provided NHS number does not match the record.",
)