Skip to main content

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; charset=utf-8".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                serde_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                        serde_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                serde_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                serde_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                serde_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                    serde_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                    serde_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                    serde_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                    serde_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                    serde_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                    serde_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                        serde_json::to_string(&invoke_response.resource).unwrap(),
184                    )
185                        .into_response()
186                }
187                InvokeResponse::Type(invoke_response) => {
188                    (
189                        StatusCode::OK,
190                        header,
191                        // Unwrap should be safe here.
192                        serde_json::to_string(&invoke_response.resource).unwrap(),
193                    )
194                        .into_response()
195                }
196                InvokeResponse::System(invoke_response) => {
197                    (
198                        StatusCode::OK,
199                        header,
200                        // Unwrap should be safe here.
201                        serde_json::to_string(&invoke_response.resource).unwrap(),
202                    )
203                        .into_response()
204                }
205            },
206
207            FHIRResponse::Delete(delete_response) => match delete_response {
208                DeleteResponse::Instance(instance_delete) => (
209                    StatusCode::OK,
210                    header,
211                    serde_json::to_string(&instance_delete.resource).unwrap(),
212                )
213                    .into_response(),
214                DeleteResponse::Type(_) => (StatusCode::NO_CONTENT, header, "").into_response(),
215                DeleteResponse::System(_) => (StatusCode::NO_CONTENT, header, "").into_response(),
216            },
217
218            FHIRResponse::Patch(fhirpatch_response) => (
219                StatusCode::OK,
220                header,
221                // Unwrap should be safe here.
222                serde_json::to_string(&fhirpatch_response.resource).unwrap(),
223            )
224                .into_response(),
225
226            FHIRResponse::Transaction(fhirtransaction_response) => {
227                (
228                    StatusCode::OK,
229                    header,
230                    // Unwrap should be safe here.
231                    serde_json::to_string(&fhirtransaction_response.resource).unwrap(),
232                )
233                    .into_response()
234            }
235        }
236    }
237}