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}