haste_server/fhir_client/middleware/
mod.rs1use crate::fhir_client::{ClientState, ServerCTX};
14use haste_fhir_client::{
15 FHIRClient,
16 request::{FHIRRequest, FHIRResponse},
17};
18use haste_fhir_operation_error::OperationOutcomeError;
19use haste_fhir_search::SearchEngine;
20use haste_fhir_terminology::FHIRTerminology;
21use haste_repository::Repository;
22use std::{pin::Pin, sync::Arc};
23
24pub mod auditing;
25pub mod auth_z;
26pub mod canonical_cache;
27pub mod capabilities;
28pub mod check_project;
29pub mod custom_models;
30pub mod element_filtering;
31pub mod operation_definitions;
32pub mod operations;
33pub mod patch_as_update;
34pub mod rate_limit;
35pub mod search_includes;
36pub mod set_artifact_tenant;
37pub mod storage;
38pub mod tenant_tier_limits;
39pub mod transaction;
40pub mod validation;
41
42pub trait Backend:
47 FHIRClient<Arc<ServerCTX<Self>>, OperationOutcomeError> + Sized + 'static
48{
49 type Repo: Repository + Send + Sync + 'static;
50 type Search: SearchEngine + Send + Sync + 'static;
51 type Terminology: FHIRTerminology + Send + Sync + 'static;
52
53 fn builtin_operations(&self) -> &operation_definitions::Builtins;
55}
56
57pub type Output<'a> =
60 Pin<Box<dyn Future<Output = Result<FHIRResponse, OperationOutcomeError>> + Send + 'a>>;
61
62pub trait Middleware<B: Backend>: Send + Sync {
65 fn call<'a>(
66 &'a self,
67 state: &'a ClientState<B>,
68 ctx: Arc<ServerCTX<B>>,
69 request: FHIRRequest,
70 next: Next<'a, B>,
71 ) -> Output<'a>;
72}
73
74pub trait Handler<B: Backend>: Send + Sync {
76 fn handle<'a>(
77 &'a self,
78 state: &'a ClientState<B>,
79 ctx: Arc<ServerCTX<B>>,
80 request: FHIRRequest,
81 ) -> Output<'a>;
82}
83
84pub struct Next<'a, B: Backend> {
87 rest: &'a [Box<dyn Middleware<B>>],
88 end: &'a dyn Handler<B>,
89}
90
91impl<B: Backend> Clone for Next<'_, B> {
92 fn clone(&self) -> Self {
93 *self
94 }
95}
96
97impl<B: Backend> Copy for Next<'_, B> {}
98
99impl<'a, B: Backend> Next<'a, B> {
100 pub fn run(
102 self,
103 state: &'a ClientState<B>,
104 ctx: Arc<ServerCTX<B>>,
105 request: FHIRRequest,
106 ) -> Output<'a> {
107 match self.rest.split_first() {
108 Some((layer, rest)) => layer.call(
109 state,
110 ctx,
111 request,
112 Next {
113 rest,
114 end: self.end,
115 },
116 ),
117 None => self.end.handle(state, ctx, request),
118 }
119 }
120}
121
122pub struct Pipeline<B: Backend> {
124 layers: Box<[Box<dyn Middleware<B>>]>,
125 end: Box<dyn Handler<B>>,
126}
127
128impl<B: Backend> Pipeline<B> {
129 pub fn new(layers: Vec<Box<dyn Middleware<B>>>, end: impl Handler<B> + 'static) -> Self {
130 Pipeline {
131 layers: layers.into_boxed_slice(),
132 end: Box::new(end),
133 }
134 }
135
136 pub fn run<'a>(
138 &'a self,
139 state: &'a ClientState<B>,
140 ctx: Arc<ServerCTX<B>>,
141 request: FHIRRequest,
142 ) -> Output<'a> {
143 Next {
144 rest: &self.layers,
145 end: self.end.as_ref(),
146 }
147 .run(state, ctx, request)
148 }
149}
150
151impl<B: Backend> Handler<B> for Pipeline<B> {
153 fn handle<'a>(
154 &'a self,
155 state: &'a ClientState<B>,
156 ctx: Arc<ServerCTX<B>>,
157 request: FHIRRequest,
158 ) -> Output<'a> {
159 self.run(state, ctx, request)
160 }
161}