Permalink
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up| /// 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(); | |
| } |