haste_fhir_client/
axum.rs

1use crate::request::{
2    DeleteResponse, FHIRResponse, HistoryResponse, InvokeResponse, SearchResponse,
3};
4use axum::response::IntoResponse;
5use haste_fhir_model::r4::generated::{
6    resources::Resource,
7    terminology::IssueType,
8    types::{FHIRId, FHIRInstant},
9};
10use haste_fhir_operation_error::OperationOutcomeError;
11use haste_reflect::MetaValue;
12use http::{HeaderMap, StatusCode};
13
14fn add_resource_headers(headers: &mut HeaderMap, resource: &Resource) -> () {
15    let _id = resource
16        .get_field("id")
17        .and_then(|id| id.as_any().downcast_ref::<String>());
18
19    let meta = resource.get_field("meta");
20
21    let last_modified = meta
22        .and_then(|meta| meta.get_field("lastUpdated"))
23        .and_then(|lu| lu.as_any().downcast_ref::<Box<FHIRInstant>>())
24        .and_then(|lu| lu.value.as_ref());
25
26    let version_id = meta
27        .and_then(|meta| meta.get_field("versionId"))
28        .and_then(|vid| vid.as_any().downcast_ref::<Box<FHIRId>>())
29        .and_then(|vid| vid.value.as_ref());
30
31    if let Some(last_modified) = last_modified {
32        headers.insert(
33            axum::http::header::LAST_MODIFIED,
34            last_modified
35                .format("%a, %d %b %G %H:%M:%S GMT")
36                .parse()
37                .unwrap(),
38        );
39    }
40    if let Some(version_id) = version_id {
41        headers.insert(
42            axum::http::header::ETAG,
43            format!("W/\"{}\"", version_id).parse().unwrap(),
44        );
45    }
46}
47
48fn add_headers(response: &FHIRResponse) -> HeaderMap {
49    let mut header = HeaderMap::new();
50    header.insert(
51        axum::http::header::CONTENT_TYPE,
52        "application/fhir+json".parse().unwrap(),
53    );
54
55    match response {
56        FHIRResponse::Create(resp) => {
57            add_resource_headers(&mut header, &resp.resource);
58        }
59        FHIRResponse::Read(resp) => {
60            if let Some(resource) = &resp.resource {
61                add_resource_headers(&mut header, resource);
62            }
63        }
64        FHIRResponse::VersionRead(resp) => {
65            add_resource_headers(&mut header, &resp.resource);
66        }
67        FHIRResponse::Update(resp) => {
68            add_resource_headers(&mut header, &resp.resource);
69        }
70        FHIRResponse::Patch(fhirpatch_response) => {
71            add_resource_headers(&mut header, &fhirpatch_response.resource);
72        }
73        _ => {}
74    };
75
76    header
77}
78
79impl IntoResponse for FHIRResponse {
80    fn into_response(self) -> axum::response::Response {
81        let header = add_headers(&self);
82
83        match self {
84            FHIRResponse::Create(response) => (
85                StatusCode::CREATED,
86                header,
87                // Unwrap should be safe here.
88                haste_fhir_serialization_json::to_string(&response.resource).unwrap(),
89            )
90                .into_response(),
91            FHIRResponse::Read(response) => {
92                if let Some(resource) = response.resource {
93                    (
94                        StatusCode::OK,
95                        header,
96                        // Unwrap should be safe here.
97                        haste_fhir_serialization_json::to_string(&resource).unwrap(),
98                    )
99                        .into_response()
100                } else {
101                    OperationOutcomeError::error(
102                        IssueType::NotFound(None),
103                        "Resource not found.".to_string(),
104                    )
105                    .into_response()
106                }
107            }
108            FHIRResponse::VersionRead(response) => (
109                StatusCode::OK,
110                header,
111                // Unwrap should be safe here.
112                haste_fhir_serialization_json::to_string(&response.resource).unwrap(),
113            )
114                .into_response(),
115            FHIRResponse::Update(response) => (
116                StatusCode::OK,
117                header,
118                // Unwrap should be safe here.
119                haste_fhir_serialization_json::to_string(&response.resource).unwrap(),
120            )
121                .into_response(),
122            FHIRResponse::Capabilities(response) => (
123                StatusCode::OK,
124                header,
125                // Unwrap should be safe here.
126                haste_fhir_serialization_json::to_string(&response.capabilities).unwrap(),
127            )
128                .into_response(),
129            FHIRResponse::History(history_response) => match history_response {
130                HistoryResponse::Instance(response) => (
131                    StatusCode::OK,
132                    header,
133                    // Unwrap should be safe here.
134                    haste_fhir_serialization_json::to_string(&response.bundle).unwrap(),
135                )
136                    .into_response(),
137                HistoryResponse::Type(response) => (
138                    StatusCode::OK,
139                    header,
140                    // Unwrap should be safe here.
141                    haste_fhir_serialization_json::to_string(&response.bundle).unwrap(),
142                )
143                    .into_response(),
144                HistoryResponse::System(response) => (
145                    StatusCode::OK,
146                    header,
147                    // Unwrap should be safe here.
148                    haste_fhir_serialization_json::to_string(&response.bundle).unwrap(),
149                )
150                    .into_response(),
151            },
152            FHIRResponse::Search(search_response) => match search_response {
153                SearchResponse::Type(response) => (
154                    StatusCode::OK,
155                    header,
156                    // Unwrap should be safe here.
157                    haste_fhir_serialization_json::to_string(&response.bundle).unwrap(),
158                )
159                    .into_response(),
160                SearchResponse::System(response) => (
161                    StatusCode::OK,
162                    header,
163                    // Unwrap should be safe here.
164                    haste_fhir_serialization_json::to_string(&response.bundle).unwrap(),
165                )
166                    .into_response(),
167            },
168            FHIRResponse::Batch(response) => {
169                (
170                    StatusCode::OK,
171                    header,
172                    // Unwrap should be safe here.
173                    haste_fhir_serialization_json::to_string(&response.resource).unwrap(),
174                )
175                    .into_response()
176            }
177            FHIRResponse::Invoke(invoke_response) => match invoke_response {
178                InvokeResponse::Instance(invoke_response) => {
179                    (
180                        StatusCode::OK,
181                        header,
182                        // Unwrap should be safe here.
183                        haste_fhir_serialization_json::to_string(&invoke_response.resource)
184                            .unwrap(),
185                    )
186                        .into_response()
187                }
188                InvokeResponse::Type(invoke_response) => {
189                    (
190                        StatusCode::OK,
191                        header,
192                        // Unwrap should be safe here.
193                        haste_fhir_serialization_json::to_string(&invoke_response.resource)
194                            .unwrap(),
195                    )
196                        .into_response()
197                }
198                InvokeResponse::System(invoke_response) => {
199                    (
200                        StatusCode::OK,
201                        header,
202                        // Unwrap should be safe here.
203                        haste_fhir_serialization_json::to_string(&invoke_response.resource)
204                            .unwrap(),
205                    )
206                        .into_response()
207                }
208            },
209
210            FHIRResponse::Delete(delete_response) => match delete_response {
211                DeleteResponse::Instance(_) => (StatusCode::NO_CONTENT, header, "").into_response(),
212                DeleteResponse::Type(_) => (StatusCode::NO_CONTENT, header, "").into_response(),
213                DeleteResponse::System(_) => (StatusCode::NO_CONTENT, header, "").into_response(),
214            },
215
216            FHIRResponse::Patch(fhirpatch_response) => (
217                StatusCode::OK,
218                header,
219                // Unwrap should be safe here.
220                haste_fhir_serialization_json::to_string(&fhirpatch_response.resource).unwrap(),
221            )
222                .into_response(),
223
224            FHIRResponse::Transaction(fhirtransaction_response) => {
225                (
226                    StatusCode::OK,
227                    header,
228                    // Unwrap should be safe here.
229                    haste_fhir_serialization_json::to_string(&fhirtransaction_response.resource)
230                        .unwrap(),
231                )
232                    .into_response()
233            }
234        }
235    }
236}