tower_web/service/
builder.rs

1use config::ConfigBuilder;
2use error::{IntoCatch, DefaultCatch};
3use futures::Future;
4use middleware::Identity;
5use net::ConnectionStream;
6use response::{DefaultSerializer, Serializer};
7use routing::{Resource, IntoResource, RoutedService};
8use service::NewWebService;
9use util::{BufStream, Chain};
10use util::http::{HttpService, HttpMiddleware};
11
12use std::io;
13use std::net::SocketAddr;
14
15/// Configure and build a web service.
16///
17/// `ServiceBuilder` collects all the components and configuration required to
18/// build the HTTP service. Once the service is defined, it can be run
19/// with `run`.
20///
21/// # Examples
22///
23/// Defining a service with a single resource;
24///
25/// ```rust
26/// # #[macro_use] extern crate tower_web;
27/// use tower_web::ServiceBuilder;
28///
29/// struct MyResource;
30///
31/// impl_web! {
32///     impl MyResource {
33///         // ...
34///     }
35/// }
36///
37/// # if false {
38/// # let addr = "127.0.0.1:8080".parse().unwrap();
39/// ServiceBuilder::new()
40///     .resource(MyResource)
41///     .run(&addr);
42/// # }
43/// ```
44///
45/// Defining a service with a multiple resources;
46///
47/// ```rust
48/// # #[macro_use] extern crate tower_web;
49/// use tower_web::ServiceBuilder;
50///
51/// struct MyResource1;
52/// struct MyResource2;
53/// struct MyResource3;
54///
55/// impl_web! {
56///     impl MyResource1 {
57///         // ...
58///     }
59///
60///     impl MyResource2 {
61///         // ...
62///     }
63///
64///     impl MyResource3 {
65///         // ...
66///     }
67/// }
68///
69/// # if false {
70/// # let addr = "127.0.0.1:8080".parse().unwrap();
71/// ServiceBuilder::new()
72///     .resource(MyResource1)
73///     .resource(MyResource2)
74///     .resource(MyResource3)
75///     .run(&addr);
76/// # }
77/// ```
78///
79/// Defining a middleware stack
80///
81/// ```rust
82/// # #[macro_use] extern crate tower_web;
83/// use tower_web::ServiceBuilder;
84/// # type FooMiddleware = tower_web::middleware::log::LogMiddleware;
85/// # type BarMiddleware = tower_web::middleware::log::LogMiddleware;
86///
87/// struct MyResource;
88///
89/// impl_web! {
90///     impl MyResource {
91///         // ...
92///     }
93/// }
94///
95/// # if false {
96/// # let addr = "127.0.0.1:8080".parse().unwrap();
97/// ServiceBuilder::new()
98///     .resource(MyResource)
99///     .middleware(FooMiddleware::new("foo"))
100///     .middleware(BarMiddleware::new("bar"))
101///     .run(&addr);
102/// # }
103/// ```
104#[derive(Debug)]
105pub struct ServiceBuilder<T, Serializer, Catch, Middleware> {
106    /// The inner resource
107    resource: T,
108    serializer: Serializer,
109    catch: Catch,
110    middleware: Middleware,
111    config: ConfigBuilder,
112}
113
114impl ServiceBuilder<(), DefaultSerializer, DefaultCatch, Identity> {
115    /// Create a new `ServiceBuilder` with default configuration.
116    ///
117    /// At least one resource must be added before building the service.
118    ///
119    /// # Examples
120    ///
121    /// ```rust
122    /// # #[macro_use] extern crate tower_web;
123    /// use tower_web::ServiceBuilder;
124    ///
125    /// struct MyResource;
126    ///
127    /// impl_web! {
128    ///     impl MyResource {
129    ///         // ...
130    ///     }
131    /// }
132    ///
133    /// # if false {
134    /// # let addr = "127.0.0.1:8080".parse().unwrap();
135    /// ServiceBuilder::new()
136    ///     .resource(MyResource)
137    ///     .run(&addr);
138    /// # }
139    /// ```
140    pub fn new() -> Self {
141        ServiceBuilder {
142            resource: (),
143            serializer: DefaultSerializer::new(),
144            catch: DefaultCatch::new(),
145            middleware: Identity::new(),
146            config: ConfigBuilder::new(),
147        }
148    }
149}
150
151impl<T, S, C, M> ServiceBuilder<T, S, C, M> {
152    /// Add a resource to the service.
153    ///
154    /// Resources are prioritized based on the order they are added to the
155    /// `ServiceBuilder`. If two resources handle the same route, then the one
156    /// that was added first gets priority.
157    ///
158    /// # Examples
159    ///
160    /// ```rust
161    /// # #[macro_use] extern crate tower_web;
162    /// use tower_web::ServiceBuilder;
163    ///
164    /// struct MyResource;
165    ///
166    /// impl_web! {
167    ///     impl MyResource {
168    ///         // ...
169    ///     }
170    /// }
171    ///
172    /// # if false {
173    /// # let addr = "127.0.0.1:8080".parse().unwrap();
174    /// ServiceBuilder::new()
175    ///     .resource(MyResource)
176    ///     .run(&addr);
177    /// # }
178    /// ```
179    pub fn resource<U>(self, resource: U)
180        -> ServiceBuilder<<T as Chain<U>>::Output, S, C, M>
181    where
182        T: Chain<U>,
183    {
184        ServiceBuilder {
185            resource: self.resource.chain(resource),
186            serializer: self.serializer,
187            catch: self.catch,
188            middleware: self.middleware,
189            config: self.config,
190        }
191    }
192
193    /// Add a serializer to the service.
194    ///
195    /// Serializers convert response structs to bytes. Each given serializer
196    /// handles a specific content-type. A service may have many registered
197    /// serializers, each handling different content-types.
198    ///
199    /// By default, the service is able to respond with "text/plain" and
200    /// "application/json" bodies. Adding new serializers adds the ability to
201    /// handle additional formats.
202    ///
203    /// Currently, the only other supported format is "text/html" and is
204    /// provided by the [handlebars] serializer. In future releases, third party
205    /// crates will be able to provide serializer implementations.
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// # #[macro_use] extern crate tower_web;
211    /// use tower_web::ServiceBuilder;
212    /// use tower_web::view::Handlebars;
213    ///
214    /// struct MyResource;
215    ///
216    /// #[derive(Response)]
217    /// #[web(template = "index")]
218    /// struct Index {
219    ///     title: &'static str,
220    /// }
221    ///
222    /// impl_web! {
223    ///     impl MyResource {
224    ///         #[get("/")]
225    ///         fn index(&self) -> Result<Index, ()> {
226    ///             Ok(Index {
227    ///                 title: "hello world",
228    ///             })
229    ///         }
230    ///     }
231    /// }
232    ///
233    /// # fn dox() {
234    /// # let addr = "127.0.0.1:0".parse().unwrap();
235    /// ServiceBuilder::new()
236    ///     .serializer(Handlebars::new())
237    ///     .resource(MyResource)
238    ///     .run(&addr);
239    /// # }
240    /// ```
241    pub fn serializer<U>(self, serializer: U)
242        -> ServiceBuilder<T, <S as Chain<U>>::Output, C, M>
243    where
244        S: Chain<U>,
245    {
246        ServiceBuilder {
247            resource: self.resource,
248            serializer: self.serializer.chain(serializer),
249            catch: self.catch,
250            middleware: self.middleware,
251            config: self.config,
252        }
253    }
254
255    /// Add a config to the service.
256    ///
257    /// Configs may be retrieved by their type and used from within extractors.
258    ///
259    /// # Examples
260    ///
261    /// ```rust
262    /// # #[macro_use] extern crate tower_web;
263    /// use tower_web::ServiceBuilder;
264    /// use tower_web::extract::{Extract, Context, Immediate};
265    /// use tower_web::util::BufStream;
266    ///
267    /// struct MyResource;
268    /// struct MyConfig {
269    ///     foo: String
270    /// }
271    /// struct MyParam {
272    ///     bar: String
273    /// }
274    ///
275    /// impl<B: BufStream> Extract<B> for MyParam {
276    ///     type Future = Immediate<MyParam>;
277    ///
278    ///     fn extract(context: &Context) -> Self::Future {
279    ///         let config = context.config::<MyConfig>().unwrap();
280    ///         let param = MyParam { bar: config.foo.clone() };
281    ///         Immediate::ok(param)
282    ///     }
283    /// }
284    ///
285    /// impl_web! {
286    ///     impl MyResource {
287    ///         #[get("/")]
288    ///         fn action(&self, param: MyParam) -> Result<String, ()> {
289    ///             Ok(param.bar)
290    ///         }
291    ///     }
292    /// }
293    ///
294    /// # if false {
295    /// # let addr = "127.0.0.1:0".parse().unwrap();
296    /// ServiceBuilder::new()
297    ///     .resource(MyResource)
298    ///     .config(MyConfig { foo: "bar".to_owned() })
299    ///     .run(&addr);
300    /// # }
301    /// ```
302    pub fn config<U>(self, config: U)
303                       -> ServiceBuilder<T, S, C, M>
304        where
305            U: Send + Sync + 'static,
306    {
307        ServiceBuilder {
308            resource: self.resource,
309            serializer: self.serializer,
310            catch: self.catch,
311            middleware: self.middleware,
312            config: self.config.insert(config),
313        }
314    }
315
316    /// Add a middleware to the service.
317    ///
318    /// Middleware that are defined last will receive requests first. In other
319    /// words, when a middleware is added to the `ServiceBuilder`, it will wrap
320    /// all previous middeware and all resources.
321    ///
322    /// # Examples
323    ///
324    /// ```rust
325    /// # #[macro_use] extern crate tower_web;
326    /// use tower_web::ServiceBuilder;
327    /// # type FooMiddleware = tower_web::middleware::log::LogMiddleware;
328    /// # type BarMiddleware = tower_web::middleware::log::LogMiddleware;
329    ///
330    /// struct MyResource;
331    ///
332    /// impl_web! {
333    ///     impl MyResource {
334    ///         // ...
335    ///     }
336    /// }
337    ///
338    /// # if false {
339    /// # let addr = "127.0.0.1:8080".parse().unwrap();
340    /// ServiceBuilder::new()
341    ///     .resource(MyResource)
342    ///     .middleware(FooMiddleware::new("foo"))
343    ///     .middleware(BarMiddleware::new("bar"))
344    ///     .run(&addr);
345    /// # }
346    /// ```
347    pub fn middleware<U>(self, middleware: U)
348        -> ServiceBuilder<T, S, C, <M as Chain<U>>::Output>
349    where
350        M: Chain<U>,
351    {
352        ServiceBuilder {
353            resource: self.resource,
354            serializer: self.serializer,
355            catch: self.catch,
356            middleware: self.middleware.chain(middleware),
357            config: self.config,
358        }
359    }
360
361    /// Add a global catch handler.
362    ///
363    /// In the event that a resource responds to a request with an error, the
364    /// catch handler has an opportunity to convert that error to a response.
365    /// Most of the time, the catch handler is used to convert the error to a
366    /// friendy response status.
367    ///
368    /// # Examples
369    ///
370    /// ```rust
371    /// # #[macro_use] extern crate tower_web;
372    /// extern crate http;
373    /// use tower_web::ServiceBuilder;
374    ///
375    /// struct MyResource;
376    ///
377    /// impl_web! {
378    ///     impl MyResource {
379    ///         // ...
380    ///     }
381    /// }
382    ///
383    /// # if false {
384    /// # let addr = "127.0.0.1:8080".parse().unwrap();
385    /// ServiceBuilder::new()
386    ///     .resource(MyResource)
387    ///     .catch(|_: &http::Request<()>, error: tower_web::Error| {
388    ///         assert!(error.status_code() == http::StatusCode::NOT_FOUND);
389    ///
390    ///         let response = http::response::Builder::new()
391    ///             .status(404)
392    ///             .header("content-type", "text/plain")
393    ///             .body("where you at?")
394    ///             .unwrap();
395    ///
396    ///         Ok(response)
397    ///     })
398    ///     .run(&addr);
399    /// # }
400    /// ```
401    pub fn catch<U>(self, catch: U) -> ServiceBuilder<T, S, U, M> {
402        ServiceBuilder {
403            resource: self.resource,
404            serializer: self.serializer,
405            catch,
406            middleware: self.middleware,
407            config: self.config,
408        }
409    }
410
411    /// Build a `NewWebService` instance
412    ///
413    /// The returned value impements `tower_service::NewService` and is used to
414    /// generate `service::WebService` values. usually, a `NewWebService`
415    /// instance is used to generate one service per TCP connection established
416    /// to the server.
417    ///
418    /// # Examples
419    ///
420    /// ```rust
421    /// # #[macro_use] extern crate tower_web;
422    /// # extern crate tower_service;
423    /// # extern crate futures;
424    /// # extern crate http;
425    ///
426    /// use tower_web::ServiceBuilder;
427    /// use tower_service::{Service, NewService};
428    /// use futures::Future;
429    ///
430    /// struct MyResource;
431    ///
432    /// impl_web! {
433    ///     impl MyResource {
434    ///         // ...
435    ///     }
436    /// }
437    ///
438    /// let new_service = ServiceBuilder::new()
439    ///     .resource(MyResource)
440    ///     .build_new_service();
441    ///
442    /// // Use `new_service` to get an instance of our web service.
443    /// let mut service = new_service.new_service()
444    ///     .wait().unwrap();
445    ///
446    /// // Issue a request to the service
447    /// let request = http::request::Builder::new()
448    ///     .method("POST")
449    ///     .uri("/hello")
450    ///     .body("hello".to_string())
451    ///     .unwrap();
452    ///
453    /// let response = service.call(request);
454    /// ```
455    pub fn build_new_service<RequestBody>(self) -> NewWebService<T::Resource, C::Catch, M>
456    where T: IntoResource<S, RequestBody>,
457          S: Serializer,
458          C: IntoCatch<S>,
459          M: HttpMiddleware<RoutedService<T::Resource, C::Catch>>,
460          RequestBody: BufStream,
461    {
462        // Build the routes
463        let routes = self.resource.routes();
464        let serializer = self.serializer;
465
466        // Create the routed service
467        let routed = RoutedService::new(
468            self.resource.into_resource(serializer),
469            self.catch.into_catch(),
470            self.config.into_config(),
471            routes);
472
473        NewWebService::new(
474            routed,
475            self.middleware)
476    }
477
478    /// Run the service
479    ///
480    /// This builds the service and passes it to Hyper to run.
481    ///
482    /// Note that Hyper requires all types to be `Send`. Thus, for this to work,
483    /// all resources must have response types that are `Send`.
484    ///
485    /// ```rust
486    /// # #[macro_use] extern crate tower_web;
487    /// use tower_web::ServiceBuilder;
488    ///
489    /// struct MyResource;
490    ///
491    /// impl_web! {
492    ///     impl MyResource {
493    ///         // ...
494    ///     }
495    /// }
496    ///
497    /// # if false {
498    /// # let addr = "127.0.0.1:8080".parse().unwrap();
499    /// ServiceBuilder::new()
500    ///     .resource(MyResource)
501    ///     .run(&addr);
502    /// # }
503    /// ```
504    pub fn run(self, addr: &SocketAddr) -> io::Result<()>
505    where T: IntoResource<S, ::run::LiftReqBody>,
506          S: Serializer,
507          C: IntoCatch<S> + Send + 'static,
508          C::Catch: Send,
509          M: HttpMiddleware<RoutedService<T::Resource, C::Catch>, RequestBody = ::run::LiftReqBody> + Send + 'static,
510          M::Service: Send,
511          <M::Service as HttpService>::Future: Send,
512          M::ResponseBody: Send,
513          <M::ResponseBody as BufStream>::Item: Send,
514          T::Resource: Send + 'static,
515          <T::Resource as Resource>::Buf: Send,
516          <T::Resource as Resource>::Body: Send,
517          <T::Resource as Resource>::Future: Send,
518    {
519        ::run::run(addr, self.build_new_service())
520    }
521
522    /// Run the service in a non-blocking mode.
523    ///
524    /// The returned `Future` object must be polled in order to process the incoming requests.
525    pub fn serve<I>(self, incoming: I) -> impl Future<Item = (), Error = ()>
526    where I: ConnectionStream,
527          I::Item: Send + 'static,
528          T: IntoResource<S, ::run::LiftReqBody>,
529          S: Serializer,
530          C: IntoCatch<S> + Send + 'static,
531          C::Catch: Send,
532          M: HttpMiddleware<RoutedService<T::Resource, C::Catch>, RequestBody = ::run::LiftReqBody> + Send + 'static,
533          M::Service: Send,
534          <M::Service as HttpService>::Future: Send,
535          M::ResponseBody: Send,
536          <M::ResponseBody as BufStream>::Item: Send,
537          T::Resource: Send + 'static,
538          <T::Resource as Resource>::Buf: Send,
539          <T::Resource as Resource>::Body: Send,
540          <T::Resource as Resource>::Future: Send,
541    {
542        ::run::serve(incoming, self.build_new_service())
543    }
544}