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