Permalink
Find file Copy path
138 lines (127 sloc) 4.44 KB
/// Hello world service.
///
/// A simple service that demonstrates how to get started with `tower-web`.
///
/// ## Overview
///
/// `tower-web` lets you define a web service using "plain old Rust types"
/// (PORT). The idea is to decouple all HTTP concepts from the business logic.
/// This is achieved by using macros that inspect the handler functions on your
/// PORT and generate a [Tower `Service`][service] implementation.
///
/// `tower-web` removes most of the boiler plate from implementing web apps by
/// embracing convention over configuration.
///
/// [service]: https://github.com/tower-rs/tower
///
/// ## Service and Resources
///
/// First, some quick terminology.
///
/// A "service" is a type that receives and responds to HTTP requests. A "route"
/// is a specific mapping from an HTTP request to a function handler. A
/// "resource" is a bundle of routes. A "service" is one or more resources.
///
/// For example, a single service might have the following resources:
///
/// * User
/// * Article
/// * Comment
///
/// Each one of those resources would have multiple routes, including, but not
/// limited to:
///
/// * User::list
/// * User::create
/// * User::update
/// * Article::show
/// * Comment::delete
///
/// ## Usage
///
/// Run the example:
///
/// cargo run --example hello_world
///
/// Then send a request:
///
/// curl -v http://localhost:8080/
#[macro_use]
extern crate tower_web;
extern crate tokio;
use tower_web::ServiceBuilder;
use tokio::prelude::*;
/// This type will be part of the web service as a resource.
#[derive(Clone, Debug)]
pub struct HelloWorld {
/// The message that will be included in the response to `/motd`.
motd: String,
}
/// To derive `Resource`, the implementation of `HelloWorld` is contained in the
/// `impl_web!` macro. This macro does not modify any of its contents. It will
/// inspect the implementation and, with the help of some annotations, generate
/// the necessary glue code to run the web service.
///
/// impl_web! is a temporary solution to enable tower-web to work with stable
/// rust. In the near future, this will be transitioned to use attribute macros.
impl_web! {
impl HelloWorld {
// `hello_world` is a plain old method on `HelloWorld`. However, note
// that there are some attributes. `impl_web` looks at these attributes
// and uses them to generate the glue code.
//
// Functions must take `&self` and return `T: IntoFuture`. Since
// `Result<_, _>` implements `IntoFuture`, it is a valid return type.
// If the function returns `Err`, it will be mapped to an HTTP 500
// response.
//
// #[get("/")] matches GET HTTP requests to `/`.
//
#[get("/")]
fn hello_world(&self) -> Result<&'static str, ()> {
Ok("This is a basic response served by tower-web")
}
// This route match GET `/motd` requests. It uses a field on
// `HelloWorld` to generate the response.
//
#[get("/motd")]
fn motd(&self) -> Result<String, ()> {
// You can also respond with an owned `String`.
Ok(format!("MOTD: {}", self.motd))
}
// Here a future is used to generate the response. This allows for
// asynchronous processing of the request.
//
// Note that the returned future must impl `Send`. Currently, hyper
// requires everything to be `Send`.
//
#[get("/hello-future")]
fn hello_future(&self) -> impl Future<Item = String, Error = ()> {
future::ok("Or return a future that resolves to the response".to_string())
}
// Other HTTP verbs are supported as well.
//
#[post("/print_std")]
fn print_std(&self) -> Result<&'static str, ()> {
println!("Hello from the web");
Ok("done")
}
}
}
pub fn main() {
// Next, we must run our web service.
//
// The HTTP service will listen on this address and port.
let addr = "127.0.0.1:8080".parse().expect("Invalid address");
println!("Listening on http://{}", addr);
// A service builder is used to configure our service.
ServiceBuilder::new()
// We add the resources that are part of the service. In this example,
// there is only a single resource.
.resource(HelloWorld {
motd: "tower-web is amazing!!!".to_string(),
})
// We run the service
.run(&addr)
.unwrap();
}