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