1use crate::{
2 auth_n::middleware::jwt::User,
3 config::ServerConfig,
4 fhir_client::{
5 middleware::{
6 ServerMiddlewareContext, ServerMiddlewareNext, ServerMiddlewareOutput,
7 ServerMiddlewareState,
8 },
9 utilities::request_to_resource_type,
10 },
11};
12use derivative::Derivative;
13use haste_fhir_client::{
14 FHIRClient,
15 middleware::{Middleware, MiddlewareChain},
16 request::{
17 DeleteRequest, DeleteResponse, FHIRBatchRequest, FHIRConditionalUpdateRequest,
18 FHIRCreateRequest, FHIRDeleteInstanceRequest, FHIRDeleteSystemRequest,
19 FHIRDeleteTypeRequest, FHIRHistoryInstanceRequest, FHIRHistorySystemRequest,
20 FHIRHistoryTypeRequest, FHIRReadRequest, FHIRRequest, FHIRResponse, FHIRSearchTypeRequest,
21 FHIRTransactionRequest, FHIRUpdateInstanceRequest, FHIRVersionReadRequest, HistoryRequest,
22 HistoryResponse, SearchRequest, SearchResponse, UpdateRequest,
23 },
24 url::ParsedParameters,
25};
26use haste_fhir_model::r4::generated::resources::{
27 Bundle, CapabilityStatement, Parameters, Resource, ResourceType,
28};
29use haste_fhir_operation_error::{OperationOutcomeError, derive::OperationOutcomeError};
30use haste_fhir_search::SearchEngine;
31use haste_fhir_terminology::FHIRTerminology;
32use haste_jwt::{
33 AuthorId, AuthorKind, ProjectId, TenantId, UserRole, VersionId,
34 claims::SubscriptionTier,
35 scopes::{
36 SMARTResourceScope, Scope, Scopes, SmartResourceScopeLevel, SmartResourceScopePermission,
37 SmartResourceScopePermissions, SmartResourceScopeUser, SmartScope,
38 },
39};
40use haste_repository::{Repository, types::SupportedFHIRVersions};
41use std::{
42 fmt::Debug,
43 sync::{Arc, LazyLock},
44};
45
46mod batch_transaction_processing;
47mod compartment;
48mod middleware;
49mod resolver;
50mod subscription_limits;
51mod utilities;
52
53#[derive(OperationOutcomeError, Debug)]
54pub enum StorageError {
55 #[error(
56 code = "not-supported",
57 diagnostic = "Storage not supported for fhir method."
58 )]
59 NotSupported,
60 #[error(
61 code = "exception",
62 diagnostic = "No response was returned from the request."
63 )]
64 NoResponse,
65 #[error(
66 code = "not-found",
67 diagnostic = "Resource '{arg0:?}' with id '{arg1}' not found."
68 )]
69 NotFound(ResourceType, String),
70 #[error(code = "invalid", diagnostic = "Invalid resource type.")]
71 InvalidType,
72}
73
74#[derive(Derivative)]
75#[derivative(Debug)]
76pub struct ServerCTX<Client: FHIRClient<Arc<Self>, OperationOutcomeError>> {
77 pub tenant: TenantId,
78 pub project: ProjectId,
79 pub fhir_version: SupportedFHIRVersions,
80 pub user: Arc<User>,
81 #[derivative(Debug = "ignore")]
82 pub client: Arc<Client>,
83 #[derivative(Debug = "ignore")]
84 pub rate_limit: Arc<dyn haste_rate_limit::RateLimit>,
85 pub tracing_id: Option<String>,
86}
87
88impl<Client: FHIRClient<Arc<Self>, OperationOutcomeError>> ServerCTX<Client> {
89 pub fn swap_client<NewClient: FHIRClient<Arc<ServerCTX<NewClient>>, OperationOutcomeError>>(
90 &self,
91 new_client: Arc<NewClient>,
92 ) -> ServerCTX<NewClient> {
93 ServerCTX {
94 tenant: self.tenant.clone(),
95 project: self.project.clone(),
96 fhir_version: self.fhir_version.clone(),
97 user: self.user.clone(),
98 client: new_client,
99 rate_limit: self.rate_limit.clone(),
100 tracing_id: self.tracing_id.clone(),
101 }
102 }
103
104 pub fn new(
105 tenant: TenantId,
106 project: ProjectId,
107 fhir_version: SupportedFHIRVersions,
108 user: Arc<User>,
109 client: Arc<Client>,
110 rate_limit: Arc<dyn haste_rate_limit::RateLimit>,
111 ) -> Self {
112 ServerCTX {
113 tenant,
114 project,
115 fhir_version,
116 user,
117 client,
118 rate_limit,
119 tracing_id: None,
120 }
121 }
122
123 pub fn system(
124 tenant: TenantId,
125 project: ProjectId,
126 client: Arc<Client>,
127 rate_limit: Arc<dyn haste_rate_limit::RateLimit>,
128 ) -> Self {
129 ServerCTX {
130 tenant: tenant.clone(),
131 project: project.clone(),
132 fhir_version: SupportedFHIRVersions::R4,
133 user: Arc::new(User {
134 token: None,
135 claims: haste_jwt::claims::UserTokenClaims {
136 sub: AuthorId::System,
137 exp: 0,
138 aud: AuthorKind::System.to_string(),
139 user_role: UserRole::Owner,
140 project: Some(project),
141 tenant,
142 subscription_tier: SubscriptionTier::Unlimited,
143 scope: Scopes(vec![Scope::SMART(SmartScope::Resource(
144 SMARTResourceScope {
145 user: SmartResourceScopeUser::System,
146 level: SmartResourceScopeLevel::AllResources,
147 permissions: SmartResourceScopePermissions::new(vec![
148 SmartResourceScopePermission::Create,
149 SmartResourceScopePermission::Read,
150 SmartResourceScopePermission::Update,
151 SmartResourceScopePermission::Delete,
152 SmartResourceScopePermission::Search,
153 ]),
154 },
155 ))]),
156 user_id: AuthorId::System,
157 resource_type: AuthorKind::System,
158 access_policy_version_ids: vec![],
159 membership: None,
160 },
161 }),
162 client,
163 rate_limit,
164 tracing_id: None,
165 }
166 }
167
168 pub fn with_tracing_id(mut self, tracing_id: Option<String>) -> Self {
169 self.tracing_id = tracing_id;
170 self
171 }
172}
173
174struct ClientState<
175 Repo: Repository + Send + Sync,
176 Search: SearchEngine + Send + Sync,
177 Terminology: FHIRTerminology + Send + Sync,
178> {
179 repo: Arc<Repo>,
180 search: Arc<Search>,
181 terminology: Arc<Terminology>,
182 audit_repo: Option<Arc<Repo>>,
183 config: Arc<ServerConfig>,
184}
185
186pub struct Route<State, Client: FHIRClient<Arc<ServerCTX<Client>>, OperationOutcomeError>> {
187 filter: Box<dyn Fn(&FHIRRequest) -> bool + Send + Sync>,
188 middleware: Middleware<
189 Arc<State>,
190 Arc<ServerCTX<Client>>,
191 FHIRRequest,
192 FHIRResponse,
193 OperationOutcomeError,
194 >,
195}
196
197pub struct FHIRServerClient<
198 Repo: Repository + Send + Sync + 'static,
199 Search: SearchEngine + Send + Sync + 'static,
200 Terminology: FHIRTerminology + Send + Sync + 'static,
201> {
202 state: Arc<ClientState<Repo, Search, Terminology>>,
203 middleware: Middleware<
204 Arc<ClientState<Repo, Search, Terminology>>,
205 Arc<ServerCTX<Self>>,
206 FHIRRequest,
207 FHIRResponse,
208 OperationOutcomeError,
209 >,
210}
211
212pub struct RouterMiddleware<
213 State,
214 Client: FHIRClient<Arc<ServerCTX<Client>>, OperationOutcomeError>,
215> {
216 routes: Arc<Vec<Route<State, Client>>>,
217}
218
219impl<State, Client: FHIRClient<Arc<ServerCTX<Client>>, OperationOutcomeError>>
220 RouterMiddleware<State, Client>
221{
222 pub fn new(routes: Arc<Vec<Route<State, Client>>>) -> Self {
223 RouterMiddleware { routes }
224 }
225}
226
227impl<
228 Repo: Repository + Send + Sync + 'static,
229 Search: SearchEngine + Send + Sync + 'static,
230 Terminology: FHIRTerminology + Send + Sync + 'static,
231 Client: FHIRClient<Arc<ServerCTX<Client>>, OperationOutcomeError> + 'static,
232>
233 MiddlewareChain<
234 ServerMiddlewareState<Repo, Search, Terminology>,
235 Arc<ServerCTX<Client>>,
236 FHIRRequest,
237 FHIRResponse,
238 OperationOutcomeError,
239 > for RouterMiddleware<ClientState<Repo, Search, Terminology>, Client>
240{
241 fn call(
242 &self,
243 state: ServerMiddlewareState<Repo, Search, Terminology>,
244 context: ServerMiddlewareContext<Client>,
245 next: Option<
246 Arc<ServerMiddlewareNext<Client, ServerMiddlewareState<Repo, Search, Terminology>>>,
247 >,
248 ) -> ServerMiddlewareOutput<Client> {
249 let routes = self.routes.clone();
250 Box::pin(async move {
251 let route = routes.iter().find(|r| (r.filter)(&context.request));
252
253 match route {
254 Some(route) => {
255 let context = route
256 .middleware
257 .call(state.clone(), context.ctx, context.request)
258 .await?;
259 if let Some(next) = next {
260 next(state, context).await
261 } else {
262 Ok(context)
263 }
264 }
265 None => {
266 if let Some(next) = next {
267 next(state, context).await
268 } else {
269 Ok(context)
270 }
271 }
272 }
273 })
274 }
275}
276
277static ARTIFACT_TYPES: &[ResourceType] = &[
278 ResourceType::ValueSet,
279 ResourceType::CodeSystem,
280 ResourceType::StructureDefinition,
281 ResourceType::SearchParameter,
282];
283
284static TENANT_AUTH_TYPES: &[ResourceType] = &[
285 ResourceType::User,
286 ResourceType::Project,
287 ResourceType::IdentityProvider,
288];
289static PROJECT_AUTH_TYPES: &[ResourceType] = &[ResourceType::Membership];
290
291static SPECIAL_TYPES: LazyLock<Vec<ResourceType>> =
292 LazyLock::new(|| [TENANT_AUTH_TYPES, PROJECT_AUTH_TYPES, ARTIFACT_TYPES].concat());
293
294pub struct ServerClientConfig<
295 Repo: Repository + Send + Sync + 'static,
296 Search: SearchEngine + Send + Sync + 'static,
297 Terminology: FHIRTerminology + Send + Sync + 'static,
298> {
299 pub repo: Arc<Repo>,
300 pub audit_repo: Option<Arc<Repo>>,
301 pub search: Arc<Search>,
302 pub terminology: Arc<Terminology>,
303 pub mutate_artifacts: bool,
304 pub config: Arc<ServerConfig>,
305}
306
307impl<
308 Repo: Repository + Send + Sync + 'static,
309 Search: SearchEngine + Send + Sync + 'static,
310 Terminology: FHIRTerminology + Send + Sync + 'static,
311> ServerClientConfig<Repo, Search, Terminology>
312{
313 pub fn new(
314 repo: Arc<Repo>,
315 search: Arc<Search>,
316 terminology: Arc<Terminology>,
317 config: Arc<ServerConfig>,
318 ) -> Self {
319 ServerClientConfig {
320 repo,
321 audit_repo: None,
322 search,
323 terminology,
324 mutate_artifacts: false,
325 config,
326 }
327 }
328
329 pub fn with_mutate_artifacts(mut self, mutate_artifacts: bool) -> Self {
330 self.mutate_artifacts = mutate_artifacts;
331 self
332 }
333
334 pub fn with_audit_repo(mut self, audit_repo: Option<Arc<Repo>>) -> Self {
335 self.audit_repo = audit_repo;
336 self
337 }
338}
339
340impl<
341 Repo: Repository + Send + Sync + 'static,
342 Search: SearchEngine + Send + Sync + 'static,
343 Terminology: FHIRTerminology + Send + Sync + 'static,
344> FHIRServerClient<Repo, Search, Terminology>
345{
346 pub fn new(config: ServerClientConfig<Repo, Search, Terminology>) -> Self {
347 let route_middleware = RouterMiddleware::new(Arc::new(vec![
348 Route {
350 filter: Box::new(|req: &FHIRRequest| match req {
351 FHIRRequest::Invocation(_) | FHIRRequest::Capabilities => false,
352 _ => {
353 if let Some(resource_type) = request_to_resource_type(req) {
354 !SPECIAL_TYPES.contains(resource_type)
355 } else {
356 true
357 }
358 }
359 }),
360 middleware: Middleware::new(vec![Box::new(middleware::storage::Middleware::new())]),
361 },
362 Route {
364 filter: Box::new(|req: &FHIRRequest| match req {
365 FHIRRequest::Create(_)
366 | FHIRRequest::Update(_)
367 | FHIRRequest::Delete(_)
368 | FHIRRequest::Read(_)
369 | FHIRRequest::Search(SearchRequest::Type(_)) => {
370 if let Some(resource_type) = request_to_resource_type(req) {
371 ARTIFACT_TYPES.contains(resource_type)
372 } else {
373 false
374 }
375 }
376 _ => false,
377 }),
378
379 middleware: Middleware::new(vec![
380 Box::new(middleware::set_artifact_tenant::Middleware::new()),
381 Box::new(middleware::storage::Middleware::new()),
382 ]),
383 },
384 Route {
386 filter: Box::new(|req: &FHIRRequest| match req {
387 FHIRRequest::Invocation(_) => true,
388 _ => false,
389 }),
390 middleware: Middleware::new(vec![Box::new(
391 middleware::operations::Middleware::new(),
392 )]),
393 },
394 Route {
396 filter: Box::new(|req: &FHIRRequest| match req {
397 FHIRRequest::Invocation(_) => false,
398 _ => request_to_resource_type(req)
399 .is_some_and(|rt| PROJECT_AUTH_TYPES.contains(rt)),
400 }),
401 middleware: Middleware::new(vec![
402 Box::new(middleware::transaction::Middleware::new()),
403 Box::new(middleware::custom_models::membership::Middleware::new()),
404 Box::new(middleware::storage::Middleware::new()),
405 ]),
406 },
407 Route {
409 filter: Box::new(|req: &FHIRRequest| match req {
410 FHIRRequest::Invocation(_) => false,
411 _ => request_to_resource_type(req)
412 .is_some_and(|rt| TENANT_AUTH_TYPES.contains(rt)),
413 }),
414 middleware: Middleware::new(vec![
415 Box::new(
416 middleware::check_project::SetProjectReadOnlyMiddleware::new(
417 ProjectId::System,
418 ),
419 ),
420 Box::new(middleware::check_project::Middleware::new(
422 ProjectId::System,
423 )),
424 Box::new(middleware::transaction::Middleware::new()),
425 Box::new(middleware::custom_models::project::Middleware::new()),
426 Box::new(middleware::custom_models::user::Middleware::new()),
427 Box::new(middleware::storage::Middleware::new()),
428 ]),
429 },
430 ]));
431
432 FHIRServerClient {
433 state: Arc::new(ClientState {
434 repo: config.repo,
435 audit_repo: config.audit_repo,
436 search: config.search,
437 terminology: config.terminology,
438 config: config.config,
439 }),
440 middleware: Middleware::new(vec![
441 Box::new(middleware::auditing::Middleware::new()),
442 Box::new(middleware::tenant_tier_limits::Middleware::new()),
443 Box::new(middleware::rate_limit::Middleware::new()),
444 Box::new(middleware::auth_z::scope_check::SMARTScopeAccessMiddleware::new()),
445 Box::new(middleware::auth_z::access_control::AccessControlMiddleware::new()),
446 Box::new(middleware::validation::Middleware::new()),
447 Box::new(route_middleware),
448 Box::new(middleware::capabilities::Middleware::new()),
449 ]),
450 }
451 }
452}
453
454impl<
455 Repo: Repository + Send + Sync + 'static,
456 Search: SearchEngine + Send + Sync + 'static,
457 Terminology: FHIRTerminology + Send + Sync + 'static,
458> FHIRClient<Arc<ServerCTX<Self>>, OperationOutcomeError>
459 for FHIRServerClient<Repo, Search, Terminology>
460{
461 #[tracing::instrument(name = "fhir_server_client", skip(self))]
462 async fn request(
463 &self,
464 _ctx: Arc<ServerCTX<Self>>,
465 request: FHIRRequest,
466 ) -> Result<FHIRResponse, OperationOutcomeError> {
467 tracing::info!("Processing request");
468 let response = self
469 .middleware
470 .call(self.state.clone(), _ctx, request)
471 .await?;
472
473 response
474 .response
475 .ok_or_else(|| StorageError::NoResponse.into())
476 }
477
478 async fn capabilities(
479 &self,
480 _ctx: Arc<ServerCTX<Self>>,
481 ) -> Result<CapabilityStatement, OperationOutcomeError> {
482 let res = self
483 .middleware
484 .call(self.state.clone(), _ctx, FHIRRequest::Capabilities)
485 .await?;
486
487 match res.response {
488 Some(FHIRResponse::Capabilities(capabilities_response)) => {
489 Ok(capabilities_response.capabilities)
490 }
491 _ => panic!("Unexpected response type"),
492 }
493 }
494
495 async fn search_system(
496 &self,
497 _ctx: Arc<ServerCTX<Self>>,
498 _parameters: ParsedParameters,
499 ) -> Result<Bundle, OperationOutcomeError> {
500 todo!()
501 }
502
503 async fn search_type(
504 &self,
505 ctx: Arc<ServerCTX<Self>>,
506 resource_type: ResourceType,
507 parameters: ParsedParameters,
508 ) -> Result<Bundle, OperationOutcomeError> {
509 let res = self
510 .middleware
511 .call(
512 self.state.clone(),
513 ctx,
514 FHIRRequest::Search(SearchRequest::Type(FHIRSearchTypeRequest {
515 resource_type,
516 parameters,
517 })),
518 )
519 .await?;
520
521 match res.response {
522 Some(FHIRResponse::Search(SearchResponse::Type(search_response))) => {
523 Ok(search_response.bundle)
524 }
525 _ => panic!("Unexpected response type"),
526 }
527 }
528
529 async fn create(
530 &self,
531 ctx: Arc<ServerCTX<Self>>,
532 resource_type: ResourceType,
533 resource: Resource,
534 ) -> Result<Resource, OperationOutcomeError> {
535 let res = self
536 .middleware
537 .call(
538 self.state.clone(),
539 ctx,
540 FHIRRequest::Create(FHIRCreateRequest {
541 resource_type,
542 resource,
543 }),
544 )
545 .await?;
546
547 match res.response {
548 Some(FHIRResponse::Create(create_response)) => Ok(create_response.resource),
549 _ => panic!("Unexpected response type"),
550 }
551 }
552
553 async fn update(
554 &self,
555 ctx: Arc<ServerCTX<Self>>,
556 resource_type: ResourceType,
557 id: String,
558 resource: Resource,
559 ) -> Result<Resource, OperationOutcomeError> {
560 let res = self
561 .middleware
562 .call(
563 self.state.clone(),
564 ctx,
565 FHIRRequest::Update(UpdateRequest::Instance(FHIRUpdateInstanceRequest {
566 resource_type,
567 id,
568 resource,
569 })),
570 )
571 .await?;
572
573 match res.response {
574 Some(FHIRResponse::Create(create_response)) => Ok(create_response.resource),
575 Some(FHIRResponse::Update(update_response)) => Ok(update_response.resource),
576 _ => panic!("Unexpected response type {:?}", res.response),
577 }
578 }
579
580 async fn conditional_update(
581 &self,
582 ctx: Arc<ServerCTX<Self>>,
583 resource_type: ResourceType,
584 parameters: ParsedParameters,
585 resource: Resource,
586 ) -> Result<Resource, OperationOutcomeError> {
587 let res = self
588 .middleware
589 .call(
590 self.state.clone(),
591 ctx,
592 FHIRRequest::Update(UpdateRequest::Conditional(FHIRConditionalUpdateRequest {
593 resource_type,
594 parameters,
595 resource,
596 })),
597 )
598 .await?;
599
600 match res.response {
601 Some(FHIRResponse::Create(create_response)) => Ok(create_response.resource),
602 Some(FHIRResponse::Update(update_response)) => Ok(update_response.resource),
603 _ => panic!("Unexpected response type {:?}", res.response),
604 }
605 }
606
607 async fn patch(
608 &self,
609 _ctx: Arc<ServerCTX<Self>>,
610 _resource_type: ResourceType,
611 _id: String,
612 _patches: json_patch::Patch,
613 ) -> Result<Resource, OperationOutcomeError> {
614 todo!()
615 }
616
617 async fn read(
618 &self,
619 ctx: Arc<ServerCTX<Self>>,
620 resource_type: ResourceType,
621 id: String,
622 ) -> Result<Option<Resource>, OperationOutcomeError> {
623 let res = self
624 .middleware
625 .call(
626 self.state.clone(),
627 ctx,
628 FHIRRequest::Read(FHIRReadRequest { resource_type, id }),
629 )
630 .await?;
631
632 match res.response {
633 Some(FHIRResponse::Read(read_response)) => Ok(read_response.resource),
634 _ => panic!("Unexpected response type"),
635 }
636 }
637
638 async fn vread(
639 &self,
640 ctx: Arc<ServerCTX<Self>>,
641 resource_type: ResourceType,
642 id: String,
643 version_id: String,
644 ) -> Result<Option<Resource>, OperationOutcomeError> {
645 let res = self
646 .middleware
647 .call(
648 self.state.clone(),
649 ctx,
650 FHIRRequest::VersionRead(FHIRVersionReadRequest {
651 resource_type,
652 id,
653 version_id: VersionId::new(version_id),
654 }),
655 )
656 .await?;
657
658 match res.response {
659 Some(FHIRResponse::VersionRead(version_read_response)) => {
660 Ok(Some(version_read_response.resource))
661 }
662 _ => panic!("Unexpected response type"),
663 }
664 }
665
666 async fn delete_instance(
667 &self,
668 ctx: Arc<ServerCTX<Self>>,
669 resource_type: ResourceType,
670 id: String,
671 ) -> Result<(), OperationOutcomeError> {
672 let res = self
673 .middleware
674 .call(
675 self.state.clone(),
676 ctx,
677 FHIRRequest::Delete(DeleteRequest::Instance(FHIRDeleteInstanceRequest {
678 resource_type,
679 id,
680 })),
681 )
682 .await?;
683
684 match res.response {
685 Some(FHIRResponse::Delete(DeleteResponse::Instance(_delete_response))) => Ok(()),
686 _ => panic!("Unexpected response type"),
687 }
688 }
689
690 async fn delete_type(
691 &self,
692 ctx: Arc<ServerCTX<Self>>,
693 resource_type: ResourceType,
694 parameters: ParsedParameters,
695 ) -> Result<(), OperationOutcomeError> {
696 let res = self
697 .middleware
698 .call(
699 self.state.clone(),
700 ctx,
701 FHIRRequest::Delete(DeleteRequest::Type(FHIRDeleteTypeRequest {
702 resource_type,
703 parameters,
704 })),
705 )
706 .await?;
707
708 match res.response {
709 Some(FHIRResponse::Delete(DeleteResponse::Type(_delete_response))) => Ok(()),
710 _ => panic!("Unexpected response type"),
711 }
712 }
713
714 async fn delete_system(
715 &self,
716 ctx: Arc<ServerCTX<Self>>,
717 parameters: ParsedParameters,
718 ) -> Result<(), OperationOutcomeError> {
719 let res = self
720 .middleware
721 .call(
722 self.state.clone(),
723 ctx,
724 FHIRRequest::Delete(DeleteRequest::System(FHIRDeleteSystemRequest {
725 parameters,
726 })),
727 )
728 .await?;
729
730 match res.response {
731 Some(FHIRResponse::Delete(DeleteResponse::System(_delete_response))) => Ok(()),
732 _ => panic!("Unexpected response type"),
733 }
734 }
735
736 async fn history_system(
737 &self,
738 ctx: Arc<ServerCTX<Self>>,
739 parameters: ParsedParameters,
740 ) -> Result<Bundle, OperationOutcomeError> {
741 let res = self
742 .middleware
743 .call(
744 self.state.clone(),
745 ctx,
746 FHIRRequest::History(HistoryRequest::System(FHIRHistorySystemRequest {
747 parameters,
748 })),
749 )
750 .await?;
751 match res.response {
752 Some(FHIRResponse::History(HistoryResponse::System(history_response))) => {
753 Ok(history_response.bundle)
754 }
755 _ => panic!("Unexpected response type"),
756 }
757 }
758
759 async fn history_type(
760 &self,
761 ctx: Arc<ServerCTX<Self>>,
762 resource_type: ResourceType,
763 parameters: ParsedParameters,
764 ) -> Result<Bundle, OperationOutcomeError> {
765 let res = self
766 .middleware
767 .call(
768 self.state.clone(),
769 ctx,
770 FHIRRequest::History(HistoryRequest::Type(FHIRHistoryTypeRequest {
771 resource_type,
772 parameters,
773 })),
774 )
775 .await?;
776 match res.response {
777 Some(FHIRResponse::History(HistoryResponse::Type(history_response))) => {
778 Ok(history_response.bundle)
779 }
780 _ => panic!("Unexpected response type"),
781 }
782 }
783
784 async fn history_instance(
785 &self,
786 ctx: Arc<ServerCTX<Self>>,
787 resource_type: ResourceType,
788 id: String,
789 parameters: ParsedParameters,
790 ) -> Result<Bundle, OperationOutcomeError> {
791 let res = self
792 .middleware
793 .call(
794 self.state.clone(),
795 ctx,
796 FHIRRequest::History(HistoryRequest::Instance(FHIRHistoryInstanceRequest {
797 resource_type,
798 id,
799 parameters,
800 })),
801 )
802 .await?;
803 match res.response {
804 Some(FHIRResponse::History(HistoryResponse::Instance(history_response))) => {
805 Ok(history_response.bundle)
806 }
807 _ => panic!("Unexpected response type"),
808 }
809 }
810
811 async fn invoke_instance(
812 &self,
813 _ctx: Arc<ServerCTX<Self>>,
814 _resource_type: ResourceType,
815 _id: String,
816 _operation: String,
817 _parameters: Parameters,
818 ) -> Result<Resource, OperationOutcomeError> {
819 todo!()
820 }
821
822 async fn invoke_type(
823 &self,
824 _ctx: Arc<ServerCTX<Self>>,
825 _resource_type: ResourceType,
826 _operation: String,
827 _parameters: Parameters,
828 ) -> Result<Resource, OperationOutcomeError> {
829 todo!()
830 }
831
832 async fn invoke_system(
833 &self,
834 _ctx: Arc<ServerCTX<Self>>,
835 _operation: String,
836 _parameters: Parameters,
837 ) -> Result<Resource, OperationOutcomeError> {
838 todo!()
839 }
840
841 async fn transaction(
842 &self,
843 ctx: Arc<ServerCTX<Self>>,
844 bundle: Bundle,
845 ) -> Result<Bundle, OperationOutcomeError> {
846 let res = self
847 .middleware
848 .call(
849 self.state.clone(),
850 ctx,
851 FHIRRequest::Transaction(FHIRTransactionRequest { resource: bundle }),
852 )
853 .await?;
854
855 match res.response {
856 Some(FHIRResponse::Transaction(transaction_response)) => {
857 Ok(transaction_response.resource)
858 }
859 _ => panic!("Unexpected response type"),
860 }
861 }
862
863 async fn batch(
864 &self,
865 ctx: Arc<ServerCTX<Self>>,
866 bundle: Bundle,
867 ) -> Result<Bundle, OperationOutcomeError> {
868 let res = self
869 .middleware
870 .call(
871 self.state.clone(),
872 ctx,
873 FHIRRequest::Batch(FHIRBatchRequest { resource: bundle }),
874 )
875 .await?;
876
877 match res.response {
878 Some(FHIRResponse::Batch(batch_response)) => Ok(batch_response.resource),
879 _ => panic!("Unexpected response type"),
880 }
881 }
882}