From fffaf2bb2de013c65d6fc282bdc9cb9895855836 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Fri, 6 Apr 2018 21:18:42 -0700 Subject: [PATCH] App::route method --- guide/src/qs_5.md | 40 ++++++++++++++++++----- src/application.rs | 79 ++++++++++++++++++++++++++++++++++++++++++---- src/route.rs | 6 ++-- 3 files changed, 108 insertions(+), 17 deletions(-) diff --git a/guide/src/qs_5.md b/guide/src/qs_5.md index 6f66af439..734931e8a 100644 --- a/guide/src/qs_5.md +++ b/guide/src/qs_5.md @@ -17,18 +17,42 @@ A resource also has a pattern, meant to match against the *PATH* portion of a *U It does not match against the *QUERY* portion (the portion following the scheme and port, e.g., */foo/bar* in the *URL* *http://localhost:8080/foo/bar?q=value*). -The [App::resource](../actix_web/struct.App.html#method.resource) methods -add a single resource to application routing table. This method accepts a *path pattern* +The [App::route](../actix_web/struct.App.html#method.route) method provides +simple way of registering routes. This method adds a single route to application +routing table. This method accepts a *path pattern*, +*http method* and a handler function. `route()` method could be called multiple times +for the same path, in that case, multiple routes register for the same resource path. + +```rust +# extern crate actix_web; +use actix_web::{App, HttpRequest, HttpResponse, http::Method}; + +fn index(req: HttpRequest) -> HttpResponse { + unimplemented!() +} + +fn main() { + App::new() + .route("/user/{name}", Method::GET, index) + .route("/user/{name}", Method::POST, index) + .finish(); +} +``` + +While *App::route()* provides simple way of registering routes, to access +complete resource configuration, different method has to be used. +The [App::resource](../actix_web/struct.App.html#method.resource) method +adds a single resource to application routing table. This method accepts a *path pattern* and a resource configuration function. ```rust # extern crate actix_web; -# use actix_web::{App, HttpRequest, HttpResponse, http::Method}; -# -# fn index(req: HttpRequest) -> HttpResponse { -# unimplemented!() -# } -# +use actix_web::{App, HttpRequest, HttpResponse, http::Method}; + +fn index(req: HttpRequest) -> HttpResponse { + unimplemented!() +} + fn main() { App::new() .resource("/prefix", |r| r.f(index)) diff --git a/src/application.rs b/src/application.rs index 9bc51ab7e..ac38668bb 100644 --- a/src/application.rs +++ b/src/application.rs @@ -3,11 +3,12 @@ use std::rc::Rc; use std::cell::UnsafeCell; use std::collections::HashMap; +use http::Method; use handler::Reply; use router::{Router, Resource}; use resource::{ResourceHandler}; use header::ContentEncoding; -use handler::{Handler, RouteHandler, WrapHandler}; +use handler::{Handler, RouteHandler, WrapHandler, FromRequest, Responder}; use httprequest::HttpRequest; use pipeline::{Pipeline, PipelineHandler, HandlerType}; use middleware::Middleware; @@ -225,6 +226,52 @@ impl App where S: 'static { self } + /// Configure route for specific path. + /// + /// This is simplified version of `App::resource()` method. + /// Handler function needs to accept one request extractor argument. + /// This method could be called multiple times, in that case multiple routes + /// would be registered for same resource path. + /// + /// ```rust + /// # extern crate actix_web; + /// use actix_web::{http, App, HttpRequest, HttpResponse}; + /// + /// fn main() { + /// let app = App::new() + /// .route("/test", http::Method::GET, + /// |_: HttpRequest| HttpResponse::Ok()) + /// .route("/test", http::Method::POST, + /// |_: HttpRequest| HttpResponse::MethodNotAllowed()); + /// } + /// ``` + pub fn route(mut self, path: &str, method: Method, f: F) -> App + where F: Fn(T) -> R + 'static, + R: Responder + 'static, + T: FromRequest + 'static, + { + { + let parts: &mut ApplicationParts = unsafe{ + mem::transmute(self.parts.as_mut().expect("Use after finish"))}; + + // get resource handler + for (pattern, handler) in &mut parts.resources { + if let Some(ref mut handler) = handler { + if pattern.pattern() == path { + handler.method(method).with(f); + return self + } + } + } + + let mut handler = ResourceHandler::default(); + handler.method(method).with(f); + let pattern = Resource::new(handler.get_name(), path); + parts.resources.push((pattern, Some(handler))); + } + self + } + /// Configure resource for specific path. /// /// Resource may have variable path also. For instance, a resource with @@ -261,12 +308,12 @@ impl App where S: 'static { { let parts = self.parts.as_mut().expect("Use after finish"); - // add resource - let mut resource = ResourceHandler::default(); - f(&mut resource); + // add resource handler + let mut handler = ResourceHandler::default(); + f(&mut handler); - let pattern = Resource::new(resource.get_name(), path); - parts.resources.push((pattern, Some(resource))); + let pattern = Resource::new(handler.get_name(), path); + parts.resources.push((pattern, Some(handler))); } self } @@ -603,6 +650,26 @@ mod tests { assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND); } + #[test] + fn test_route() { + let mut app = App::new() + .route("/test", Method::GET, |_: HttpRequest| HttpResponse::Ok()) + .route("/test", Method::POST, |_: HttpRequest| HttpResponse::Created()) + .finish(); + + let req = TestRequest::with_uri("/test").method(Method::GET).finish(); + let resp = app.run(req); + assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + + let req = TestRequest::with_uri("/test").method(Method::POST).finish(); + let resp = app.run(req); + assert_eq!(resp.as_response().unwrap().status(), StatusCode::CREATED); + + let req = TestRequest::with_uri("/test").method(Method::HEAD).finish(); + let resp = app.run(req); + assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND); + } + #[test] fn test_handler_prefix() { let mut app = App::new() diff --git a/src/route.rs b/src/route.rs index a2c1947e4..86614c0e1 100644 --- a/src/route.rs +++ b/src/route.rs @@ -102,7 +102,7 @@ impl Route { self.handler = InnerHandler::async(handler); } - /// Set handler function with http request extractor. + /// Set handler function, use request extractor for paramters. /// /// ```rust /// # extern crate bytes; @@ -137,7 +137,7 @@ impl Route { cfg } - /// Set handler function, function has to accept two request extractors. + /// Set handler function, use request extractor for both paramters. /// /// ```rust /// # extern crate bytes; @@ -180,7 +180,7 @@ impl Route { (cfg1, cfg2) } - /// Set handler function, function has to accept three request extractors. + /// Set handler function, use request extractor for all paramters. pub fn with3(&mut self, handler: F) -> (ExtractorConfig, ExtractorConfig, ExtractorConfig) where F: Fn(T1, T2, T3) -> R + 'static,