Skip to main content

haste_fhir_client/
http.rs

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                    // Parameters for invoke are passed in the body as a Parameters resource.
544                    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                    // Parameters for invoke are passed in the body as a Parameters resource.
572                    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                    // Parameters for invoke are passed in the body as a Parameters resource.
599                    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}