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