1use crate::{
2 FHIRClient,
3 middleware::{Context, Middleware, MiddlewareChain, Next},
4 request::{
5 self, DeleteRequest, DeleteResponse, FHIRCreateResponse, FHIRPatchResponse,
6 FHIRReadResponse, FHIRRequest, FHIRResponse, HistoryRequest, HistoryResponse,
7 InvocationRequest, InvokeResponse, Operation, SearchRequest, SearchResponse, UpdateRequest,
8 },
9 url::{ParsedParameter, ParsedParameters},
10};
11use derivative::Derivative;
12use haste_fhir_model::r4::generated::{
13 resources::{
14 Bundle, CapabilityStatement, OperationOutcome, Parameters, Resource, ResourceType,
15 },
16 terminology::IssueType,
17};
18use haste_fhir_operation_error::{OperationOutcomeError, derive::OperationOutcomeError};
19use haste_jwt::VersionId;
20use http::HeaderValue;
21use reqwest::Url;
22use std::{fmt::Debug, pin::Pin, sync::Arc};
23
24#[derive(Derivative)]
25#[derivative(Debug)]
26pub struct FHIRHttpState {
27 #[derivative(Debug = "ignore")]
28 client: reqwest::Client,
29 api_url: Url,
30 #[derivative(Debug = "ignore")]
31 get_access_token: Option<
32 Arc<
33 dyn Fn() -> Pin<
34 Box<dyn Future<Output = Result<String, OperationOutcomeError>> + Send + Sync>,
35 > + Sync
36 + Send,
37 >,
38 >,
39}
40
41impl FHIRHttpState {
42 pub fn new(
43 api_url: &str,
44 get_access_token: Option<
45 Arc<
46 dyn Fn() -> Pin<
47 Box<
48 dyn Future<Output = Result<String, OperationOutcomeError>>
49 + Send
50 + Sync,
51 >,
52 > + Sync
53 + Send,
54 >,
55 >,
56 ) -> Result<Self, OperationOutcomeError> {
57 let url =
58 Url::parse(api_url).map_err(|_| FHIRHTTPError::UrlParseError(api_url.to_string()))?;
59 Ok(FHIRHttpState {
60 client: reqwest::Client::new(),
61 api_url: url,
62 get_access_token,
63 })
64 }
65}
66
67pub struct FHIRHttpClient<CTX: Debug> {
68 state: Arc<FHIRHttpState>,
69 middleware:
70 Middleware<Arc<FHIRHttpState>, CTX, FHIRRequest, FHIRResponse, OperationOutcomeError>,
71}
72
73#[derive(Debug, OperationOutcomeError)]
74pub enum FHIRHTTPError {
75 #[error(code = "exception", diagnostic = "Reqwest failed.")]
76 ReqwestError(#[from] reqwest::Error),
77 #[error(code = "not-supported", diagnostic = "Operation not supported.")]
78 NotSupported,
79 #[fatal(code = "exception", diagnostic = "No response received.")]
80 NoResponse,
81 #[fatal(
82 code = "exception",
83 diagnostic = "Invalid url that could not be parsed {arg0}"
84 )]
85 UrlParseError(String),
86 #[error(code = "invalid", diagnostic = "FHIR Deserialization Error '{arg0}'.")]
87 DeserializeError(#[from] haste_fhir_serialization_json::errors::DeserializeError),
88 #[error(code = "invalid", diagnostic = "FHIR Serialization Error.")]
89 SerializeError(#[from] haste_fhir_serialization_json::SerializeError),
90 #[error(code = "invalid", diagnostic = "FHIR Serialization Error.")]
91 JSONSerializeError(#[from] serde_json::Error),
92}
93
94fn fhir_parameter_to_query_parameters(http_url: &mut reqwest::Url, parameters: &ParsedParameters) {
95 let mut query_parameters = http_url.query_pairs_mut();
96 for parameter in parameters.parameters() {
97 let parameter = match parameter {
98 ParsedParameter::Result(parameter) | ParsedParameter::Resource(parameter) => parameter,
99 };
100
101 let mut query_param_name = parameter.name.clone();
102
103 if let Some(chains) = parameter.chains.as_ref() {
104 query_param_name = format!("{}.{}", query_param_name, chains.join("."));
105 }
106
107 if let Some(modifier) = parameter.modifier.as_ref() {
108 query_param_name = format!("{}:{}", query_param_name, modifier);
109 }
110
111 query_parameters.append_pair(&query_param_name, parameter.value.join(",").as_str());
112 }
113}
114
115fn fhir_request_to_http_request<'a>(
116 state: &'a FHIRHttpState,
117 request: &'a FHIRRequest,
118) -> Pin<Box<dyn Future<Output = Result<reqwest::Request, OperationOutcomeError>> + Send + 'a>> {
119 Box::pin(async move {
120 let request: Result<reqwest::Request, OperationOutcomeError> = match request {
121 FHIRRequest::Read(read_request) => {
122 let read_request_url = state
123 .api_url
124 .join(&format!(
125 "{}/{}/{}",
126 state.api_url.path(),
127 read_request.resource_type.as_ref(),
128 read_request.id
129 ))
130 .map_err(|_e| FHIRHTTPError::UrlParseError("Read request".to_string()))?;
131
132 let request = state
133 .client
134 .get(read_request_url)
135 .header("Accept", "application/fhir+json")
136 .header("Content-Type", "application/fhir+json, application/json")
137 .build()
138 .map_err(FHIRHTTPError::from)?;
139
140 Ok(request)
141 }
142 FHIRRequest::Compartment(compartment_request) => {
143 let compartment_url = state
144 .api_url
145 .join(&format!(
146 "{}/{}/{}",
147 state.api_url.path(),
148 compartment_request.resource_type.as_ref(),
149 compartment_request.id
150 ))
151 .map_err(|_e| {
152 FHIRHTTPError::UrlParseError("Compartment request".to_string())
153 })?;
154
155 let request = fhir_request_to_http_request(
156 &FHIRHttpState {
157 api_url: compartment_url,
158 client: state.client.clone(),
159 get_access_token: state.get_access_token.clone(),
160 },
161 &compartment_request.request,
162 )
163 .await?;
164
165 Ok(request)
166 }
167 FHIRRequest::Create(create_request) => {
168 let create_request_url = state
169 .api_url
170 .join(&format!(
171 "{}/{}",
172 state.api_url.path(),
173 create_request.resource_type.as_ref(),
174 ))
175 .map_err(|_e| FHIRHTTPError::UrlParseError("Create request".to_string()))?;
176
177 let body =
178 serde_json::to_string(&create_request.resource).map_err(FHIRHTTPError::from)?;
179
180 let request = state
181 .client
182 .post(create_request_url)
183 .header("Accept", "application/fhir+json")
184 .header("Content-Type", "application/fhir+json, application/json")
185 .body(body)
186 .build()
187 .map_err(FHIRHTTPError::from)?;
188
189 Ok(request)
190 }
191 FHIRRequest::Patch(patch_request) => {
192 let patch_request_url = state
193 .api_url
194 .join(&format!(
195 "{}/{}/{}",
196 state.api_url.path(),
197 patch_request.resource_type.as_ref(),
198 patch_request.id
199 ))
200 .map_err(|_e| FHIRHTTPError::UrlParseError("Patch request".to_string()))?;
201
202 let patch_body =
203 serde_json::to_string(&patch_request.patch).map_err(FHIRHTTPError::from)?;
204
205 let request = state
206 .client
207 .patch(patch_request_url)
208 .header("Accept", "application/fhir+json")
209 .header("Content-Type", "application/fhir+json, application/json")
210 .body(patch_body)
211 .build()
212 .map_err(FHIRHTTPError::from)?;
213
214 Ok(request)
215 }
216 FHIRRequest::Transaction(transaction_request) => {
217 let body = serde_json::to_string(&transaction_request.resource)
218 .map_err(FHIRHTTPError::from)?;
219
220 let request = state
221 .client
222 .post(state.api_url.clone())
223 .header("Accept", "application/fhir+json")
224 .header("Content-Type", "application/fhir+json, application/json")
225 .body(body)
226 .build()
227 .map_err(FHIRHTTPError::from)?;
228
229 Ok(request)
230 }
231 FHIRRequest::VersionRead(version_request) => {
232 let version_request_url = state
233 .api_url
234 .join(&format!(
235 "{}/{}/{}/_history/{}",
236 state.api_url.path(),
237 version_request.resource_type.as_ref(),
238 version_request.id,
239 version_request.version_id.as_ref(),
240 ))
241 .map_err(|_e| FHIRHTTPError::UrlParseError("Patch request".to_string()))?;
242
243 let request = state
244 .client
245 .get(version_request_url)
246 .header("Accept", "application/fhir+json")
247 .header("Content-Type", "application/fhir+json, application/json")
248 .build()
249 .map_err(FHIRHTTPError::from)?;
250
251 Ok(request)
252 }
253
254 FHIRRequest::Update(update_request) => match &update_request {
255 UpdateRequest::Instance(update_request) => {
256 let update_request_url = state
257 .api_url
258 .join(&format!(
259 "{}/{}/{}",
260 state.api_url.path(),
261 update_request.resource_type.as_ref(),
262 update_request.id
263 ))
264 .map_err(|_e| FHIRHTTPError::UrlParseError("Update request".to_string()))?;
265
266 let request = state
267 .client
268 .put(update_request_url)
269 .header("Accept", "application/fhir+json")
270 .header("Content-Type", "application/fhir+json, application/json")
271 .body(
272 serde_json::to_string(&update_request.resource)
273 .map_err(FHIRHTTPError::from)?,
274 )
275 .build()
276 .map_err(FHIRHTTPError::from)?;
277
278 Ok(request)
279 }
280 UpdateRequest::Conditional(fhirconditional_update_request) => {
281 let mut request_url = state
282 .api_url
283 .join(&format!(
284 "{}/{}",
285 state.api_url.path(),
286 fhirconditional_update_request.resource_type.as_ref(),
287 ))
288 .map_err(|_e| {
289 FHIRHTTPError::UrlParseError("ConditionalUpdate request".to_string())
290 })?;
291 fhir_parameter_to_query_parameters(
292 &mut request_url,
293 &fhirconditional_update_request.parameters,
294 );
295
296 let request = state
297 .client
298 .put(request_url)
299 .header("Accept", "application/fhir+json")
300 .header("Content-Type", "application/fhir+json, application/json")
301 .body(
302 serde_json::to_string(&fhirconditional_update_request.resource)
303 .map_err(FHIRHTTPError::from)?,
304 )
305 .build()
306 .map_err(FHIRHTTPError::from)?;
307
308 Ok(request)
309 }
310 },
311
312 FHIRRequest::Search(search_request) => match &search_request {
313 SearchRequest::Type(search_type_request) => {
314 let mut request_url = state
315 .api_url
316 .join(&format!(
317 "{}/{}",
318 state.api_url.path(),
319 search_type_request.resource_type.as_ref(),
320 ))
321 .map_err(|_e| {
322 FHIRHTTPError::UrlParseError("SearchType request".to_string())
323 })?;
324
325 fhir_parameter_to_query_parameters(
326 &mut request_url,
327 &search_type_request.parameters,
328 );
329
330 let request = state
331 .client
332 .get(request_url)
333 .header("Accept", "application/fhir+json")
334 .header("Content-Type", "application/fhir+json, application/json")
335 .build()
336 .map_err(FHIRHTTPError::from)?;
337
338 Ok(request)
339 }
340 SearchRequest::System(fhirsearch_system_request) => {
341 let mut request_url =
342 state.api_url.join(state.api_url.path()).map_err(|_e| {
343 FHIRHTTPError::UrlParseError("SearchSystem request".to_string())
344 })?;
345
346 fhir_parameter_to_query_parameters(
347 &mut request_url,
348 &fhirsearch_system_request.parameters,
349 );
350
351 let request = state
352 .client
353 .get(request_url)
354 .header("Accept", "application/fhir+json")
355 .header("Content-Type", "application/fhir+json, application/json")
356 .build()
357 .map_err(FHIRHTTPError::from)?;
358
359 Ok(request)
360 }
361 },
362 FHIRRequest::Delete(delete_request) => match delete_request {
363 DeleteRequest::Instance(fhirdelete_instance_request) => {
364 let delete_request_url = state
365 .api_url
366 .join(&format!(
367 "{}/{}/{}",
368 state.api_url.path(),
369 fhirdelete_instance_request.resource_type.as_ref(),
370 fhirdelete_instance_request.id
371 ))
372 .map_err(|_e| {
373 FHIRHTTPError::UrlParseError("DeleteInstance request".to_string())
374 })?;
375
376 let request = state
377 .client
378 .delete(delete_request_url)
379 .header("Accept", "application/fhir+json")
380 .header("Content-Type", "application/fhir+json, application/json")
381 .build()
382 .map_err(FHIRHTTPError::from)?;
383
384 Ok(request)
385 }
386 DeleteRequest::Type(fhirdelete_type_request) => {
387 let mut request_url = state
388 .api_url
389 .join(&format!(
390 "{}/{}",
391 state.api_url.path(),
392 fhirdelete_type_request.resource_type.as_ref(),
393 ))
394 .map_err(|_e| {
395 FHIRHTTPError::UrlParseError("DeleteType request".to_string())
396 })?;
397
398 fhir_parameter_to_query_parameters(
399 &mut request_url,
400 &fhirdelete_type_request.parameters,
401 );
402
403 let request = state
404 .client
405 .delete(request_url)
406 .header("Accept", "application/fhir+json")
407 .header("Content-Type", "application/fhir+json, application/json")
408 .build()
409 .map_err(FHIRHTTPError::from)?;
410
411 Ok(request)
412 }
413 DeleteRequest::System(fhirdelete_system_request) => {
414 let mut request_url =
415 state.api_url.join(state.api_url.path()).map_err(|_e| {
416 FHIRHTTPError::UrlParseError("DeleteSystem request".to_string())
417 })?;
418
419 fhir_parameter_to_query_parameters(
420 &mut request_url,
421 &fhirdelete_system_request.parameters,
422 );
423
424 let request = state
425 .client
426 .delete(request_url)
427 .header("Accept", "application/fhir+json")
428 .header("Content-Type", "application/fhir+json, application/json")
429 .build()
430 .map_err(FHIRHTTPError::from)?;
431
432 Ok(request)
433 }
434 },
435 FHIRRequest::Capabilities => {
436 let request = state
437 .client
438 .get(format!("{}/metadata", state.api_url))
439 .header("Accept", "application/fhir+json")
440 .header("Content-Type", "application/fhir+json, application/json")
441 .build()
442 .map_err(FHIRHTTPError::from)?;
443
444 Ok(request)
445 }
446
447 FHIRRequest::History(history_request) => match history_request {
448 HistoryRequest::Instance(fhirhistory_instance_request) => {
449 let mut request_url = state
450 .api_url
451 .join(&format!(
452 "{}/{}/{}/_history",
453 state.api_url.path(),
454 fhirhistory_instance_request.resource_type.as_ref(),
455 fhirhistory_instance_request.id
456 ))
457 .map_err(|_e| {
458 FHIRHTTPError::UrlParseError("HistoryInstance request".to_string())
459 })?;
460
461 fhir_parameter_to_query_parameters(
462 &mut request_url,
463 &fhirhistory_instance_request.parameters,
464 );
465
466 let request = state
467 .client
468 .get(request_url)
469 .header("Accept", "application/fhir+json")
470 .header("Content-Type", "application/fhir+json, application/json")
471 .build()
472 .map_err(FHIRHTTPError::from)?;
473
474 Ok(request)
475 }
476 HistoryRequest::Type(fhirhistory_type_request) => {
477 let mut request_url = state
478 .api_url
479 .join(&format!(
480 "{}/{}/_history",
481 state.api_url.path(),
482 fhirhistory_type_request.resource_type.as_ref(),
483 ))
484 .map_err(|_e| {
485 FHIRHTTPError::UrlParseError("HistoryType request".to_string())
486 })?;
487
488 fhir_parameter_to_query_parameters(
489 &mut request_url,
490 &fhirhistory_type_request.parameters,
491 );
492
493 let request = state
494 .client
495 .get(request_url)
496 .header("Accept", "application/fhir+json")
497 .header("Content-Type", "application/fhir+json, application/json")
498 .build()
499 .map_err(FHIRHTTPError::from)?;
500
501 Ok(request)
502 }
503 HistoryRequest::System(fhirhistory_system_request) => {
504 let mut request_url = state
505 .api_url
506 .join(&format!("{}/_history", state.api_url.path()))
507 .map_err(|_e| {
508 FHIRHTTPError::UrlParseError("HistorySystem request".to_string())
509 })?;
510
511 fhir_parameter_to_query_parameters(
512 &mut request_url,
513 &fhirhistory_system_request.parameters,
514 );
515
516 let request = state
517 .client
518 .get(request_url)
519 .header("Accept", "application/fhir+json")
520 .header("Content-Type", "application/fhir+json, application/json")
521 .build()
522 .map_err(FHIRHTTPError::from)?;
523
524 Ok(request)
525 }
526 },
527
528 FHIRRequest::Invocation(invoke_request) => match invoke_request {
529 InvocationRequest::Instance(fhirinvoke_instance_request) => {
530 let request_url = state
531 .api_url
532 .join(&format!(
533 "{}/{}/{}/${}",
534 state.api_url.path(),
535 fhirinvoke_instance_request.resource_type.as_ref(),
536 fhirinvoke_instance_request.id,
537 fhirinvoke_instance_request.operation.name(),
538 ))
539 .map_err(|_e| {
540 FHIRHTTPError::UrlParseError("InvokeInstance request".to_string())
541 })?;
542
543 let body = serde_json::to_string(&fhirinvoke_instance_request.parameters)
545 .map_err(FHIRHTTPError::from)?;
546
547 let request = state
548 .client
549 .post(request_url)
550 .header("Accept", "application/fhir+json")
551 .header("Content-Type", "application/fhir+json, application/json")
552 .body(body)
553 .build()
554 .map_err(FHIRHTTPError::from)?;
555
556 Ok(request)
557 }
558 InvocationRequest::Type(fhirinvoke_type_request) => {
559 let request_url = state
560 .api_url
561 .join(&format!(
562 "{}/{}/${}",
563 state.api_url.path(),
564 fhirinvoke_type_request.resource_type.as_ref(),
565 fhirinvoke_type_request.operation.name(),
566 ))
567 .map_err(|_e| {
568 FHIRHTTPError::UrlParseError("InvokeType request".to_string())
569 })?;
570
571 let body = serde_json::to_string(&fhirinvoke_type_request.parameters)
573 .map_err(FHIRHTTPError::from)?;
574
575 let request = state
576 .client
577 .post(request_url)
578 .header("Accept", "application/fhir+json")
579 .header("Content-Type", "application/fhir+json, application/json")
580 .body(body)
581 .build()
582 .map_err(FHIRHTTPError::from)?;
583
584 Ok(request)
585 }
586 InvocationRequest::System(fhirinvoke_system_request) => {
587 let request_url = state
588 .api_url
589 .join(&format!(
590 "{}/${}",
591 state.api_url.path(),
592 fhirinvoke_system_request.operation.name(),
593 ))
594 .map_err(|_e| {
595 FHIRHTTPError::UrlParseError("InvokeSystem request".to_string())
596 })?;
597
598 let body = serde_json::to_string(&fhirinvoke_system_request.parameters)
600 .map_err(FHIRHTTPError::from)?;
601
602 let request = state
603 .client
604 .post(request_url)
605 .header("Accept", "application/fhir+json")
606 .header("Content-Type", "application/fhir+json, application/json")
607 .body(body)
608 .build()
609 .map_err(FHIRHTTPError::from)?;
610
611 Ok(request)
612 }
613 },
614 FHIRRequest::Batch(fhirbatch_request) => {
615 let body = serde_json::to_string(&fhirbatch_request.resource)
616 .map_err(FHIRHTTPError::from)?;
617
618 let request = state
619 .client
620 .post(state.api_url.clone())
621 .header("Accept", "application/fhir+json")
622 .header("Content-Type", "application/fhir+json, application/json")
623 .body(body)
624 .build()
625 .map_err(FHIRHTTPError::from)?;
626
627 Ok(request)
628 }
629 };
630
631 let mut request = request?;
632
633 if let Some(get_access_token) = state.get_access_token.as_ref() {
634 let token = get_access_token().await?;
635
636 request.headers_mut().insert(
637 "Authorization",
638 HeaderValue::from_str(&format!("Bearer {}", token)).map_err(|_| {
639 OperationOutcomeError::error(
640 IssueType::Invalid(None),
641 "Failed to create Authorization header.".to_string(),
642 )
643 })?,
644 );
645 }
646
647 Ok(request)
648 })
649}
650
651async fn check_for_errors(
652 status: &reqwest::StatusCode,
653 body: Option<&[u8]>,
654) -> Result<(), OperationOutcomeError> {
655 if !status.is_success() {
656 if let Some(body) = body
657 && let Ok(operation_outcome) = serde_json::from_slice::<OperationOutcome>(&body)
658 {
659 return Err(OperationOutcomeError::new(None, operation_outcome));
660 }
661
662 return Err(OperationOutcomeError::error(
663 IssueType::Exception(None),
664 format!("HTTP returned error '{}'.", status),
665 ));
666 }
667 Ok(())
668}
669
670fn http_response_to_fhir_response<'a>(
671 fhir_request: &'a FHIRRequest,
672 response: reqwest::Response,
673) -> Pin<Box<dyn Future<Output = Result<FHIRResponse, OperationOutcomeError>> + 'a + Send>> {
674 Box::pin(async move {
675 match fhir_request {
676 FHIRRequest::Read(_) => {
677 let status = response.status();
678 let body = response
679 .bytes()
680 .await
681 .map_err(FHIRHTTPError::ReqwestError)?;
682
683 check_for_errors(&status, Some(&body)).await?;
684
685 let resource =
686 serde_json::from_slice::<Resource>(&body).map_err(FHIRHTTPError::from)?;
687 Ok(FHIRResponse::Read(FHIRReadResponse {
688 resource: Some(resource),
689 }))
690 }
691 FHIRRequest::Compartment(compartment_request) => {
692 http_response_to_fhir_response(&compartment_request.request, response).await
693 }
694 FHIRRequest::Create(_) => {
695 let status = response.status();
696 let body = response
697 .bytes()
698 .await
699 .map_err(FHIRHTTPError::ReqwestError)?;
700
701 check_for_errors(&status, Some(&body)).await?;
702
703 let resource =
704 serde_json::from_slice::<Resource>(&body).map_err(FHIRHTTPError::from)?;
705 Ok(FHIRResponse::Create(FHIRCreateResponse { resource }))
706 }
707 FHIRRequest::Patch(_) => {
708 let status = response.status();
709 let body = response
710 .bytes()
711 .await
712 .map_err(FHIRHTTPError::ReqwestError)?;
713
714 check_for_errors(&status, Some(&body)).await?;
715
716 let resource =
717 serde_json::from_slice::<Resource>(&body).map_err(FHIRHTTPError::from)?;
718 Ok(FHIRResponse::Patch(FHIRPatchResponse { resource }))
719 }
720 FHIRRequest::Transaction(_) => {
721 let status = response.status();
722 let body = response
723 .bytes()
724 .await
725 .map_err(FHIRHTTPError::ReqwestError)?;
726
727 check_for_errors(&status, Some(&body)).await?;
728
729 let resource =
730 serde_json::from_slice::<Bundle>(&body).map_err(FHIRHTTPError::from)?;
731
732 Ok(FHIRResponse::Transaction(
733 request::FHIRTransactionResponse { resource },
734 ))
735 }
736 FHIRRequest::VersionRead(_) => {
737 let status = response.status();
738 let body = response
739 .bytes()
740 .await
741 .map_err(FHIRHTTPError::ReqwestError)?;
742
743 check_for_errors(&status, Some(&body)).await?;
744
745 let resource =
746 serde_json::from_slice::<Resource>(&body).map_err(FHIRHTTPError::from)?;
747 Ok(FHIRResponse::VersionRead(
748 request::FHIRVersionReadResponse { resource },
749 ))
750 }
751 FHIRRequest::Update(update_request) => match &update_request {
752 UpdateRequest::Instance(_) => {
753 let status = response.status();
754 let body = response
755 .bytes()
756 .await
757 .map_err(FHIRHTTPError::ReqwestError)?;
758
759 check_for_errors(&status, Some(&body)).await?;
760
761 let resource =
762 serde_json::from_slice::<Resource>(&body).map_err(FHIRHTTPError::from)?;
763
764 Ok(FHIRResponse::Update(request::FHIRUpdateResponse {
765 resource,
766 }))
767 }
768 UpdateRequest::Conditional(_) => {
769 let status = response.status();
770 let body = response
771 .bytes()
772 .await
773 .map_err(FHIRHTTPError::ReqwestError)?;
774
775 check_for_errors(&status, Some(&body)).await?;
776
777 let resource =
778 serde_json::from_slice::<Resource>(&body).map_err(FHIRHTTPError::from)?;
779
780 Ok(FHIRResponse::Update(request::FHIRUpdateResponse {
781 resource,
782 }))
783 }
784 },
785
786 FHIRRequest::Delete(delete_request) => match delete_request {
787 DeleteRequest::Instance(_) => {
788 let status = response.status();
789 let body = response
790 .bytes()
791 .await
792 .map_err(FHIRHTTPError::ReqwestError)?;
793
794 check_for_errors(&status, Some(&body)).await?;
795
796 let resource =
797 serde_json::from_slice::<Resource>(&body).map_err(FHIRHTTPError::from)?;
798
799 Ok(FHIRResponse::Delete(DeleteResponse::Instance(
800 request::FHIRDeleteInstanceResponse { resource },
801 )))
802 }
803 DeleteRequest::Type(_) => {
804 let status = response.status();
805 let body = response
806 .bytes()
807 .await
808 .map_err(FHIRHTTPError::ReqwestError)?;
809
810 check_for_errors(&status, Some(&body)).await?;
811
812 Ok(FHIRResponse::Delete(DeleteResponse::Type(
813 request::FHIRDeleteTypeResponse {},
814 )))
815 }
816 DeleteRequest::System(_) => {
817 let status = response.status();
818 let body = response
819 .bytes()
820 .await
821 .map_err(FHIRHTTPError::ReqwestError)?;
822
823 check_for_errors(&status, Some(&body)).await?;
824
825 Ok(FHIRResponse::Delete(DeleteResponse::System(
826 request::FHIRDeleteSystemResponse {},
827 )))
828 }
829 },
830 FHIRRequest::Capabilities => {
831 let status = response.status();
832 let body = response
833 .bytes()
834 .await
835 .map_err(FHIRHTTPError::ReqwestError)?;
836
837 check_for_errors(&status, Some(&body)).await?;
838
839 let capabilities = serde_json::from_slice::<CapabilityStatement>(&body)
840 .map_err(FHIRHTTPError::from)?;
841
842 Ok(FHIRResponse::Capabilities(
843 request::FHIRCapabilitiesResponse { capabilities },
844 ))
845 }
846
847 FHIRRequest::Search(search_request) => match search_request {
848 SearchRequest::Type(_) => {
849 let status = response.status();
850 let body = response
851 .bytes()
852 .await
853 .map_err(FHIRHTTPError::ReqwestError)?;
854
855 check_for_errors(&status, Some(&body)).await?;
856
857 let bundle =
858 serde_json::from_slice::<Bundle>(&body).map_err(FHIRHTTPError::from)?;
859
860 Ok(FHIRResponse::Search(SearchResponse::Type(
861 request::FHIRSearchTypeResponse { bundle },
862 )))
863 }
864 SearchRequest::System(_) => {
865 let status = response.status();
866 let body = response
867 .bytes()
868 .await
869 .map_err(FHIRHTTPError::ReqwestError)?;
870
871 check_for_errors(&status, Some(&body)).await?;
872
873 let bundle =
874 serde_json::from_slice::<Bundle>(&body).map_err(FHIRHTTPError::from)?;
875
876 Ok(FHIRResponse::Search(SearchResponse::System(
877 request::FHIRSearchSystemResponse { bundle },
878 )))
879 }
880 },
881
882 FHIRRequest::History(history_request) => match history_request {
883 HistoryRequest::Instance(_) => {
884 let status = response.status();
885 let body = response
886 .bytes()
887 .await
888 .map_err(FHIRHTTPError::ReqwestError)?;
889
890 check_for_errors(&status, Some(&body)).await?;
891
892 let bundle =
893 serde_json::from_slice::<Bundle>(&body).map_err(FHIRHTTPError::from)?;
894
895 Ok(FHIRResponse::History(HistoryResponse::Instance(
896 request::FHIRHistoryInstanceResponse { bundle },
897 )))
898 }
899 HistoryRequest::Type(_) => {
900 let status = response.status();
901 let body = response
902 .bytes()
903 .await
904 .map_err(FHIRHTTPError::ReqwestError)?;
905
906 check_for_errors(&status, Some(&body)).await?;
907
908 let bundle =
909 serde_json::from_slice::<Bundle>(&body).map_err(FHIRHTTPError::from)?;
910
911 Ok(FHIRResponse::History(HistoryResponse::Type(
912 request::FHIRHistoryTypeResponse { bundle },
913 )))
914 }
915 HistoryRequest::System(_) => {
916 let status = response.status();
917 let body = response
918 .bytes()
919 .await
920 .map_err(FHIRHTTPError::ReqwestError)?;
921
922 check_for_errors(&status, Some(&body)).await?;
923
924 let bundle =
925 serde_json::from_slice::<Bundle>(&body).map_err(FHIRHTTPError::from)?;
926
927 Ok(FHIRResponse::History(HistoryResponse::System(
928 request::FHIRHistorySystemResponse { bundle },
929 )))
930 }
931 },
932
933 FHIRRequest::Invocation(invoke_request) => match invoke_request {
934 InvocationRequest::Instance(_) => {
935 let status = response.status();
936 let body = response
937 .bytes()
938 .await
939 .map_err(FHIRHTTPError::ReqwestError)?;
940
941 check_for_errors(&status, Some(&body)).await?;
942
943 let resource =
944 serde_json::from_slice::<Resource>(&body).map_err(FHIRHTTPError::from)?;
945
946 Ok(FHIRResponse::Invoke(InvokeResponse::Instance(
947 request::FHIRInvokeInstanceResponse { resource },
948 )))
949 }
950 InvocationRequest::Type(_) => {
951 let status = response.status();
952 let body = response
953 .bytes()
954 .await
955 .map_err(FHIRHTTPError::ReqwestError)?;
956
957 check_for_errors(&status, Some(&body)).await?;
958
959 let resource =
960 serde_json::from_slice::<Resource>(&body).map_err(FHIRHTTPError::from)?;
961
962 Ok(FHIRResponse::Invoke(InvokeResponse::Type(
963 request::FHIRInvokeTypeResponse { resource },
964 )))
965 }
966 InvocationRequest::System(_) => {
967 let status = response.status();
968 let body = response
969 .bytes()
970 .await
971 .map_err(FHIRHTTPError::ReqwestError)?;
972
973 check_for_errors(&status, Some(&body)).await?;
974
975 let resource =
976 serde_json::from_slice::<Resource>(&body).map_err(FHIRHTTPError::from)?;
977
978 Ok(FHIRResponse::Invoke(InvokeResponse::System(
979 request::FHIRInvokeSystemResponse { resource },
980 )))
981 }
982 },
983
984 FHIRRequest::Batch(_) => {
985 let status = response.status();
986 let body = response
987 .bytes()
988 .await
989 .map_err(FHIRHTTPError::ReqwestError)?;
990
991 check_for_errors(&status, Some(&body)).await?;
992
993 let resource =
994 serde_json::from_slice::<Bundle>(&body).map_err(FHIRHTTPError::from)?;
995
996 Ok(FHIRResponse::Batch(request::FHIRBatchResponse { resource }))
997 }
998 }
999 })
1000}
1001
1002struct HTTPMiddleware {}
1003impl HTTPMiddleware {
1004 fn new() -> Self {
1005 HTTPMiddleware {}
1006 }
1007}
1008impl<CTX: Send + 'static + Debug>
1009 MiddlewareChain<Arc<FHIRHttpState>, CTX, FHIRRequest, FHIRResponse, OperationOutcomeError>
1010 for HTTPMiddleware
1011{
1012 fn call(
1013 &self,
1014 state: Arc<FHIRHttpState>,
1015 context: Context<CTX, FHIRRequest, FHIRResponse>,
1016 _next: Option<
1017 Arc<
1018 Next<
1019 Arc<FHIRHttpState>,
1020 Context<CTX, FHIRRequest, FHIRResponse>,
1021 OperationOutcomeError,
1022 >,
1023 >,
1024 >,
1025 ) -> Pin<
1026 Box<
1027 dyn Future<
1028 Output = Result<Context<CTX, FHIRRequest, FHIRResponse>, OperationOutcomeError>,
1029 > + Send,
1030 >,
1031 > {
1032 Box::pin(async move {
1033 let http_request = fhir_request_to_http_request(&state, &context.request).await?;
1034 let response = state
1035 .client
1036 .execute(http_request)
1037 .await
1038 .map_err(FHIRHTTPError::ReqwestError)?;
1039
1040 let mut next_context = context;
1041 let fhir_response =
1042 http_response_to_fhir_response(&next_context.request, response).await?;
1043 next_context.response = Some(fhir_response);
1044
1045 Ok(next_context)
1046 })
1047 }
1048}
1049
1050impl<CTX: 'static + Send + Sync + Debug> FHIRHttpClient<CTX> {
1051 pub fn new(state: FHIRHttpState) -> Self {
1052 let middleware = Middleware::new(vec![Box::new(HTTPMiddleware::new())]);
1053 FHIRHttpClient {
1054 state: Arc::new(state),
1055 middleware,
1056 }
1057 }
1058}
1059
1060impl<CTX: 'static + Send + Sync + Debug> FHIRClient<CTX, OperationOutcomeError>
1061 for FHIRHttpClient<CTX>
1062{
1063 async fn request(
1064 &self,
1065 ctx: CTX,
1066 request: crate::request::FHIRRequest,
1067 ) -> Result<crate::request::FHIRResponse, OperationOutcomeError> {
1068 let response = self
1069 .middleware
1070 .call(self.state.clone(), ctx, request)
1071 .await?;
1072
1073 response
1074 .response
1075 .ok_or_else(|| FHIRHTTPError::NoResponse.into())
1076 }
1077
1078 async fn capabilities(&self, _ctx: CTX) -> Result<CapabilityStatement, OperationOutcomeError> {
1079 let res = self
1080 .middleware
1081 .call(self.state.clone(), _ctx, FHIRRequest::Capabilities)
1082 .await?;
1083
1084 match res.response {
1085 Some(FHIRResponse::Capabilities(capabilities_response)) => {
1086 Ok(capabilities_response.capabilities)
1087 }
1088 _ => Err(FHIRHTTPError::NoResponse.into()),
1089 }
1090 }
1091
1092 async fn search_system(
1093 &self,
1094 ctx: CTX,
1095 parameters: crate::ParsedParameters,
1096 ) -> Result<Bundle, OperationOutcomeError> {
1097 let res = self
1098 .middleware
1099 .call(
1100 self.state.clone(),
1101 ctx,
1102 FHIRRequest::Search(SearchRequest::System(request::FHIRSearchSystemRequest {
1103 parameters,
1104 })),
1105 )
1106 .await?;
1107 match res.response {
1108 Some(FHIRResponse::Search(SearchResponse::System(search_system_response))) => {
1109 Ok(search_system_response.bundle)
1110 }
1111 _ => Err(FHIRHTTPError::NoResponse.into()),
1112 }
1113 }
1114
1115 async fn search_type(
1116 &self,
1117 ctx: CTX,
1118 resource_type: ResourceType,
1119 parameters: crate::ParsedParameters,
1120 ) -> Result<Bundle, OperationOutcomeError> {
1121 let res = self
1122 .middleware
1123 .call(
1124 self.state.clone(),
1125 ctx,
1126 FHIRRequest::Search(SearchRequest::Type(request::FHIRSearchTypeRequest {
1127 resource_type,
1128 parameters,
1129 })),
1130 )
1131 .await?;
1132 match res.response {
1133 Some(FHIRResponse::Search(SearchResponse::Type(search_type_response))) => {
1134 Ok(search_type_response.bundle)
1135 }
1136 _ => Err(FHIRHTTPError::NoResponse.into()),
1137 }
1138 }
1139
1140 async fn create(
1141 &self,
1142 ctx: CTX,
1143 resource_type: ResourceType,
1144 resource: Resource,
1145 ) -> Result<Resource, OperationOutcomeError> {
1146 let res = self
1147 .middleware
1148 .call(
1149 self.state.clone(),
1150 ctx,
1151 FHIRRequest::Create(request::FHIRCreateRequest {
1152 resource_type,
1153 resource,
1154 }),
1155 )
1156 .await?;
1157
1158 match res.response {
1159 Some(FHIRResponse::Create(create_response)) => Ok(create_response.resource),
1160 _ => Err(FHIRHTTPError::NoResponse.into()),
1161 }
1162 }
1163
1164 async fn update(
1165 &self,
1166 ctx: CTX,
1167 resource_type: ResourceType,
1168 id: String,
1169 resource: Resource,
1170 ) -> Result<Resource, OperationOutcomeError> {
1171 let res = self
1172 .middleware
1173 .call(
1174 self.state.clone(),
1175 ctx,
1176 FHIRRequest::Update(UpdateRequest::Instance(
1177 request::FHIRUpdateInstanceRequest {
1178 resource_type,
1179 id,
1180 resource,
1181 },
1182 )),
1183 )
1184 .await?;
1185 match res.response {
1186 Some(FHIRResponse::Update(update_response)) => Ok(update_response.resource),
1187 _ => Err(FHIRHTTPError::NoResponse.into()),
1188 }
1189 }
1190
1191 async fn conditional_update(
1192 &self,
1193 ctx: CTX,
1194 resource_type: ResourceType,
1195 parameters: crate::ParsedParameters,
1196 resource: Resource,
1197 ) -> Result<Resource, OperationOutcomeError> {
1198 let res = self
1199 .middleware
1200 .call(
1201 self.state.clone(),
1202 ctx,
1203 FHIRRequest::Update(UpdateRequest::Conditional(
1204 request::FHIRConditionalUpdateRequest {
1205 resource_type,
1206 parameters,
1207 resource,
1208 },
1209 )),
1210 )
1211 .await?;
1212 match res.response {
1213 Some(FHIRResponse::Update(update_response)) => Ok(update_response.resource),
1214 _ => Err(FHIRHTTPError::NoResponse.into()),
1215 }
1216 }
1217
1218 async fn patch(
1219 &self,
1220 ctx: CTX,
1221 resource_type: ResourceType,
1222 id: String,
1223 patch: json_patch::Patch,
1224 ) -> Result<Resource, OperationOutcomeError> {
1225 let res = self
1226 .middleware
1227 .call(
1228 self.state.clone(),
1229 ctx,
1230 FHIRRequest::Patch(request::FHIRPatchRequest {
1231 resource_type,
1232 id,
1233 patch,
1234 }),
1235 )
1236 .await?;
1237
1238 match res.response {
1239 Some(FHIRResponse::Patch(patch_response)) => Ok(patch_response.resource),
1240 _ => Err(FHIRHTTPError::NoResponse.into()),
1241 }
1242 }
1243
1244 async fn read(
1245 &self,
1246 ctx: CTX,
1247 resource_type: ResourceType,
1248 id: String,
1249 ) -> Result<Option<Resource>, OperationOutcomeError> {
1250 let res = self
1251 .middleware
1252 .call(
1253 self.state.clone(),
1254 ctx,
1255 FHIRRequest::Read(request::FHIRReadRequest { resource_type, id }),
1256 )
1257 .await?;
1258
1259 match res.response {
1260 Some(FHIRResponse::Read(read_response)) => Ok(read_response.resource),
1261 _ => Err(FHIRHTTPError::NoResponse.into()),
1262 }
1263 }
1264
1265 async fn vread(
1266 &self,
1267 ctx: CTX,
1268 resource_type: ResourceType,
1269 id: String,
1270 version_id: String,
1271 ) -> Result<Option<Resource>, OperationOutcomeError> {
1272 let res = self
1273 .middleware
1274 .call(
1275 self.state.clone(),
1276 ctx,
1277 FHIRRequest::VersionRead(request::FHIRVersionReadRequest {
1278 resource_type,
1279 id,
1280 version_id: VersionId::new(version_id),
1281 }),
1282 )
1283 .await?;
1284
1285 match res.response {
1286 Some(FHIRResponse::VersionRead(version_read_response)) => {
1287 Ok(Some(version_read_response.resource))
1288 }
1289 _ => Err(FHIRHTTPError::NoResponse.into()),
1290 }
1291 }
1292
1293 async fn delete_instance(
1294 &self,
1295 ctx: CTX,
1296 resource_type: ResourceType,
1297 id: String,
1298 ) -> Result<(), OperationOutcomeError> {
1299 let res = self
1300 .middleware
1301 .call(
1302 self.state.clone(),
1303 ctx,
1304 FHIRRequest::Delete(DeleteRequest::Instance(
1305 request::FHIRDeleteInstanceRequest { resource_type, id },
1306 )),
1307 )
1308 .await?;
1309
1310 match res.response {
1311 Some(FHIRResponse::Delete(_delete_instance_response)) => Ok(()),
1312 _ => Err(FHIRHTTPError::NoResponse.into()),
1313 }
1314 }
1315
1316 async fn delete_type(
1317 &self,
1318 ctx: CTX,
1319 resource_type: ResourceType,
1320 parameters: crate::ParsedParameters,
1321 ) -> Result<(), OperationOutcomeError> {
1322 let res = self
1323 .middleware
1324 .call(
1325 self.state.clone(),
1326 ctx,
1327 FHIRRequest::Delete(DeleteRequest::Type(request::FHIRDeleteTypeRequest {
1328 resource_type,
1329 parameters,
1330 })),
1331 )
1332 .await?;
1333 match res.response {
1334 Some(FHIRResponse::Delete(_delete_type_response)) => Ok(()),
1335 _ => Err(FHIRHTTPError::NoResponse.into()),
1336 }
1337 }
1338
1339 async fn delete_system(
1340 &self,
1341 ctx: CTX,
1342 parameters: crate::ParsedParameters,
1343 ) -> Result<(), OperationOutcomeError> {
1344 let res = self
1345 .middleware
1346 .call(
1347 self.state.clone(),
1348 ctx,
1349 FHIRRequest::Delete(DeleteRequest::System(request::FHIRDeleteSystemRequest {
1350 parameters,
1351 })),
1352 )
1353 .await?;
1354 match res.response {
1355 Some(FHIRResponse::Delete(_delete_system_response)) => Ok(()),
1356 _ => Err(FHIRHTTPError::NoResponse.into()),
1357 }
1358 }
1359
1360 async fn history_system(
1361 &self,
1362 ctx: CTX,
1363 parameters: crate::ParsedParameters,
1364 ) -> Result<Bundle, OperationOutcomeError> {
1365 let res = self
1366 .middleware
1367 .call(
1368 self.state.clone(),
1369 ctx,
1370 FHIRRequest::History(HistoryRequest::System(request::FHIRHistorySystemRequest {
1371 parameters,
1372 })),
1373 )
1374 .await?;
1375
1376 match res.response {
1377 Some(FHIRResponse::History(HistoryResponse::System(history_system_response))) => {
1378 Ok(history_system_response.bundle)
1379 }
1380 _ => Err(FHIRHTTPError::NoResponse.into()),
1381 }
1382 }
1383
1384 async fn history_type(
1385 &self,
1386 ctx: CTX,
1387 resource_type: ResourceType,
1388 parameters: crate::ParsedParameters,
1389 ) -> Result<Bundle, OperationOutcomeError> {
1390 let res = self
1391 .middleware
1392 .call(
1393 self.state.clone(),
1394 ctx,
1395 FHIRRequest::History(HistoryRequest::Type(request::FHIRHistoryTypeRequest {
1396 resource_type,
1397 parameters,
1398 })),
1399 )
1400 .await?;
1401
1402 match res.response {
1403 Some(FHIRResponse::History(HistoryResponse::Type(history_type_response))) => {
1404 Ok(history_type_response.bundle)
1405 }
1406 _ => Err(FHIRHTTPError::NoResponse.into()),
1407 }
1408 }
1409
1410 async fn history_instance(
1411 &self,
1412 ctx: CTX,
1413 resource_type: ResourceType,
1414 id: String,
1415 parameters: crate::ParsedParameters,
1416 ) -> Result<Bundle, OperationOutcomeError> {
1417 let res = self
1418 .middleware
1419 .call(
1420 self.state.clone(),
1421 ctx,
1422 FHIRRequest::History(HistoryRequest::Instance(
1423 request::FHIRHistoryInstanceRequest {
1424 resource_type,
1425 id,
1426 parameters,
1427 },
1428 )),
1429 )
1430 .await?;
1431
1432 match res.response {
1433 Some(FHIRResponse::History(HistoryResponse::Instance(history_instance_response))) => {
1434 Ok(history_instance_response.bundle)
1435 }
1436 _ => Err(FHIRHTTPError::NoResponse.into()),
1437 }
1438 }
1439
1440 async fn invoke_instance(
1441 &self,
1442 ctx: CTX,
1443 resource_type: ResourceType,
1444 id: String,
1445 operation: String,
1446 parameters: Parameters,
1447 ) -> Result<Resource, OperationOutcomeError> {
1448 let res = self
1449 .middleware
1450 .call(
1451 self.state.clone(),
1452 ctx,
1453 FHIRRequest::Invocation(InvocationRequest::Instance(
1454 request::FHIRInvokeInstanceRequest {
1455 resource_type,
1456 id,
1457 operation: Operation::new(&operation).map_err(|_e| {
1458 OperationOutcomeError::error(
1459 IssueType::Exception(None),
1460 "invalid operation".to_string(),
1461 )
1462 })?,
1463 parameters,
1464 },
1465 )),
1466 )
1467 .await?;
1468
1469 match res.response {
1470 Some(FHIRResponse::Invoke(InvokeResponse::Instance(invoke_instance_response))) => {
1471 Ok(invoke_instance_response.resource)
1472 }
1473 _ => Err(FHIRHTTPError::NoResponse.into()),
1474 }
1475 }
1476
1477 async fn invoke_type(
1478 &self,
1479 ctx: CTX,
1480 resource_type: ResourceType,
1481 operation: String,
1482 parameters: Parameters,
1483 ) -> Result<Resource, OperationOutcomeError> {
1484 let res = self
1485 .middleware
1486 .call(
1487 self.state.clone(),
1488 ctx,
1489 FHIRRequest::Invocation(InvocationRequest::Type(request::FHIRInvokeTypeRequest {
1490 resource_type,
1491 operation: Operation::new(&operation).map_err(|_e| {
1492 OperationOutcomeError::error(
1493 IssueType::Exception(None),
1494 "invalid operation".to_string(),
1495 )
1496 })?,
1497 parameters,
1498 })),
1499 )
1500 .await?;
1501
1502 match res.response {
1503 Some(FHIRResponse::Invoke(InvokeResponse::Type(invoke_type_response))) => {
1504 Ok(invoke_type_response.resource)
1505 }
1506 _ => Err(FHIRHTTPError::NoResponse.into()),
1507 }
1508 }
1509
1510 async fn invoke_system(
1511 &self,
1512 ctx: CTX,
1513 operation: String,
1514 parameters: Parameters,
1515 ) -> Result<Resource, OperationOutcomeError> {
1516 let res = self
1517 .middleware
1518 .call(
1519 self.state.clone(),
1520 ctx,
1521 FHIRRequest::Invocation(InvocationRequest::System(
1522 request::FHIRInvokeSystemRequest {
1523 operation: Operation::new(&operation).map_err(|_e| {
1524 OperationOutcomeError::error(
1525 IssueType::Exception(None),
1526 "invalid operation".to_string(),
1527 )
1528 })?,
1529 parameters,
1530 },
1531 )),
1532 )
1533 .await?;
1534
1535 match res.response {
1536 Some(FHIRResponse::Invoke(InvokeResponse::System(invoke_system_response))) => {
1537 Ok(invoke_system_response.resource)
1538 }
1539 _ => Err(FHIRHTTPError::NoResponse.into()),
1540 }
1541 }
1542
1543 async fn transaction(&self, ctx: CTX, bundle: Bundle) -> Result<Bundle, OperationOutcomeError> {
1544 let res = self
1545 .middleware
1546 .call(
1547 self.state.clone(),
1548 ctx,
1549 FHIRRequest::Transaction(request::FHIRTransactionRequest { resource: bundle }),
1550 )
1551 .await?;
1552
1553 match res.response {
1554 Some(FHIRResponse::Transaction(transaction_response)) => {
1555 Ok(transaction_response.resource)
1556 }
1557 _ => Err(FHIRHTTPError::NoResponse.into()),
1558 }
1559 }
1560
1561 async fn batch(&self, ctx: CTX, bundle: Bundle) -> Result<Bundle, OperationOutcomeError> {
1562 let res = self
1563 .middleware
1564 .call(
1565 self.state.clone(),
1566 ctx,
1567 FHIRRequest::Batch(request::FHIRBatchRequest { resource: bundle }),
1568 )
1569 .await?;
1570
1571 match res.response {
1572 Some(FHIRResponse::Batch(batch_response)) => Ok(batch_response.resource),
1573 _ => Err(FHIRHTTPError::NoResponse.into()),
1574 }
1575 }
1576}