tosic_http/server/
builder.rs

1//! The [`HttpServerBuilder`] is a builder for configuring and initializing an [`HttpServer`].
2//! It allows for setting up the server address, adding services, and configuring shared state.
3
4use crate::body::BoxBody;
5use crate::error::Error;
6use crate::handlers::Handlers;
7use crate::server::HttpServer;
8use crate::services::HttpService;
9use crate::state::State;
10use crate::traits::from_request::FromRequest;
11use crate::traits::handler::Handler;
12use crate::traits::responder::Responder;
13use http::Method;
14use std::fmt::Debug;
15use std::future::Future;
16use tokio::io;
17use tokio::net::ToSocketAddrs;
18
19use crate::prelude::{HttpPayload, HttpRequest, HttpResponse};
20use crate::resource::RouteBuilder;
21use crate::route::HandlerFn;
22#[allow(unused_imports)]
23use std::any::TypeId;
24#[allow(unused_imports)]
25use std::collections::HashMap;
26use tower::layer::util::{Identity, Stack};
27use tower::{Layer, Service, ServiceBuilder};
28
29#[derive(Debug, Clone)]
30/// [`HttpServerBuilder`] is a builder for configuring and initializing an [`HttpServer`].
31/// It allows for setting up the server address, adding services, and configuring shared state.
32pub struct HttpServerBuilder<T, L>
33where
34    T: ToSocketAddrs + Default + Clone,
35    L: Layer<HandlerFn> + Clone + Send + 'static,
36{
37    addr: Option<T>,
38    handlers: Handlers,
39    app_state: State,
40    service_builder: ServiceBuilder<L>,
41}
42
43impl<T: ToSocketAddrs + Default + Debug + Clone> Default for HttpServerBuilder<T, Identity> {
44    fn default() -> Self {
45        Self {
46            addr: None,
47            handlers: Handlers::new(),
48            app_state: State::new(),
49            service_builder: ServiceBuilder::new(),
50        }
51    }
52}
53
54impl<T: ToSocketAddrs + Default + Debug + Clone> HttpServerBuilder<T, Identity> {
55    pub(crate) fn new() -> HttpServerBuilder<T, Identity> {
56        Self::default()
57    }
58}
59
60impl<T, L> HttpServerBuilder<T, L>
61where
62    T: ToSocketAddrs + Default + Debug + Clone,
63    L: Layer<HandlerFn> + Clone + Send + 'static,
64    L::Service: Service<(HttpRequest, HttpPayload), Response = HttpResponse, Error = Error>
65        + Send
66        + 'static,
67    <L::Service as Service<(HttpRequest, HttpPayload)>>::Future: Send + 'static,
68{
69    /// Adds shared application state to be accessible in request handlers.
70    ///
71    /// State is stored in a [`HashMap`] and keyed based on the [`TypeId`] of the state object.
72    ///
73    /// # Arguments
74    /// - `state`: A state object of type `S` that implements `Send + Sync + 'static`.
75    ///
76    /// # Returns
77    /// The builder instance with the shared state added.
78    ///
79    /// # Examples
80    /// ```
81    /// # use tosic_http::prelude::HttpServer;
82    /// struct MyState {
83    ///     state: String
84    /// }
85    ///
86    /// let builder = HttpServer::builder()
87    ///     .with_state(MyState { state: "Hello, world!".to_string() })
88    ///     .bind("127.0.0.1:8080");
89    /// ```
90    pub fn app_state<S: Send + Sync + 'static>(self, state: S) -> Self {
91        self.app_state.insert(state);
92
93        self
94    }
95
96    /// Adds a service handler to the server.
97    ///
98    /// # Arguments
99    ///
100    /// - `method`: The HTTP method for the service endpoint.
101    /// - `path`: The path of the service endpoint.
102    /// - `handler`: A handler implementing the [`Handler`] trait, defining a service endpoint.
103    ///
104    /// # Returns
105    ///
106    /// The builder instance with the handler added.
107    ///
108    /// # Examples
109    /// ```
110    /// # use tosic_http::prelude::{HttpServer, Responder, HttpResponse, BoxBody, Method};
111    ///
112    /// async fn basic_handler() -> impl Responder<Body = BoxBody> {
113    ///     HttpResponse::new(200)
114    /// }
115    ///
116    /// let builder = HttpServer::builder()
117    ///     .service_method(Method::GET, "/", basic_handler)
118    ///     .bind("127.0.0.1:8080");
119    /// ```
120    pub fn service_method<H, Args>(mut self, method: Method, path: &str, handler: H) -> Self
121    where
122        H: Handler<Args> + Send + Sync + 'static,
123        Args: FromRequest + Send + 'static,
124        Args::Future: Future + Send + 'static,
125        H::Future: Future + Send + 'static,
126        H::Output: Responder<Body = BoxBody> + 'static,
127        Error: From<Args::Error>,
128    {
129        self.handlers.insert(method, path, handler);
130        self
131    }
132
133    /// Adds a service handler to the server.
134    ///
135    /// # Arguments
136    ///
137    /// - `handler`: A handler implementing the [`Handler`] & [`HttpService`] traits.
138    ///
139    /// # Returns
140    ///
141    /// The builder instance with the handler added.
142    ///
143    /// # Examples
144    /// ```
145    /// # use tosic_http::prelude::{HttpServer, Responder, HttpResponse, BoxBody, Method, get};
146    ///
147    /// #[get("/")]
148    /// async fn basic_handler() -> impl Responder<Body = BoxBody> {
149    ///     HttpResponse::new(200)
150    /// }
151    ///
152    /// let builder = HttpServer::builder()
153    ///     .service(basic_handler)
154    ///     .bind("127.0.0.1:8080");
155    /// ```
156    pub fn service<H, Args>(mut self, handler: H) -> Self
157    where
158        H: HttpService<Args> + Handler<Args> + Send + Sync + 'static,
159        Args: FromRequest + Send + 'static,
160        Args::Future: Future + Send + 'static,
161        H::Future: Future + Send + 'static,
162        H::Output: Responder<Body = BoxBody> + 'static,
163        Error: From<Args::Error>,
164    {
165        self.handlers.insert(H::METHOD, H::PATH, handler);
166        self
167    }
168
169    /// Adds a route to the server.
170    ///
171    /// # Arguments
172    ///
173    /// - `route_builder`: A builder for defining the route.
174    ///
175    /// # Returns
176    ///
177    /// The builder instance with the route added.
178    ///
179    pub fn route(mut self, route_builder: RouteBuilder) -> Self {
180        self.handlers.extend(route_builder.handlers());
181
182        self
183    }
184
185    /// Sets the address the server will bind to.
186    ///
187    /// # Arguments
188    ///
189    /// - `addr`: The address for the server to bind, implementing [`ToSocketAddrs`].
190    ///
191    /// # Returns
192    ///
193    /// Returns the builder instance with the binding address set.
194    ///
195    /// # Examples
196    /// ```
197    /// # use tosic_http::prelude::HttpServer;
198    /// let builder = HttpServer::builder()
199    ///     .bind("127.0.0.1:8080");
200    /// ```
201    pub fn bind(mut self, addr: T) -> Self {
202        self.addr = Some(addr);
203        self
204    }
205
206    /// Builds and initializes the [`HttpServer`] with the current configuration.
207    ///
208    /// # Errors
209    /// Returns [`io::Error`] if there was an error initializing the server.
210    ///
211    /// # Examples
212    /// ```
213    /// # use tosic_http::prelude::HttpServer;
214    /// # #[tokio::main]
215    /// # async fn main() {
216    /// let server = HttpServer::builder()
217    ///     .bind("127.0.0.1:8080")
218    ///     .build()
219    ///     .await
220    ///     .unwrap();
221    /// # }
222    /// ```
223    pub async fn build(self) -> io::Result<HttpServer<L>> {
224        let addr = self.addr.unwrap_or_default();
225
226        HttpServer::new(addr, self.handlers, self.app_state, self.service_builder).await
227    }
228
229    /// Wraps a layer in the stack.
230    ///
231    /// A layer is a middleware that can modify the request and response.
232    pub fn wrap<S>(self, layer: S) -> HttpServerBuilder<T, Stack<S, L>>
233    where
234        S: Layer<HandlerFn> + Clone + Send + 'static,
235        L: Layer<S::Service> + Clone + Send + 'static,
236    {
237        HttpServerBuilder {
238            addr: self.addr,
239            handlers: self.handlers,
240            app_state: self.app_state,
241            service_builder: self.service_builder.layer(layer),
242        }
243    }
244}