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