Skip to main content

haste_server/fhir_client/
mod.rs

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            // Clinical resources.
349            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            // Artifact routes.
363            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            // Operation routes
385            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            // Authentication routes.
395            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            // Tenant auth routes.
408            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                    // Confirm in system project as above will only set to system if readonly.
421                    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}