1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-06-25 09:59:21 +02:00

simplify Application creation; update url dispatch guide section

This commit is contained in:
Nikolay Kim
2017-12-11 14:16:29 -08:00
parent caca907c23
commit 0f75d066f2
24 changed files with 512 additions and 207 deletions

View File

@ -69,13 +69,11 @@ impl Application<()> {
/// Create application with empty state. Application can
/// be configured with builder-like pattern.
///
/// This method accepts path prefix for which it should serve requests.
pub fn new<T: Into<String>>(prefix: T) -> Application<()> {
pub fn new() -> Application<()> {
Application {
parts: Some(ApplicationParts {
state: (),
prefix: prefix.into(),
prefix: "/".to_owned(),
default: Resource::default_not_found(),
resources: HashMap::new(),
external: HashMap::new(),
@ -85,6 +83,12 @@ impl Application<()> {
}
}
impl Default for Application<()> {
fn default() -> Self {
Application::new()
}
}
impl<S> Application<S> where S: 'static {
/// Create application with specific state. Application can be
@ -92,11 +96,11 @@ impl<S> Application<S> where S: 'static {
///
/// State is shared with all reousrces within same application and could be
/// accessed with `HttpRequest::state()` method.
pub fn with_state<T: Into<String>>(prefix: T, state: S) -> Application<S> {
pub fn with_state(state: S) -> Application<S> {
Application {
parts: Some(ApplicationParts {
state: state,
prefix: prefix.into(),
prefix: "/".to_owned(),
default: Resource::default_not_found(),
resources: HashMap::new(),
external: HashMap::new(),
@ -105,6 +109,42 @@ impl<S> Application<S> where S: 'static {
}
}
/// Set application prefix.
///
/// Only requests that matches application's prefix get processed by this application.
/// Application prefix always contains laading "/" slash. If supplied prefix
/// does not contain leading slash, it get inserted.
///
/// Inthe following example only requests with "/app/" path prefix
/// get handled. Request with path "/app/test/" will be handled,
/// but request with path "/other/..." will return *NOT FOUND*
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::*;
///
/// fn main() {
/// let app = Application::new()
/// .prefix("/app")
/// .resource("/test", |r| {
/// r.method(Method::GET).f(|_| httpcodes::HTTPOk);
/// r.method(Method::HEAD).f(|_| httpcodes::HTTPMethodNotAllowed);
/// })
/// .finish();
/// }
/// ```
pub fn prefix<P: Into<String>>(&mut self, prefix: P) -> &mut Self {
{
let parts = self.parts.as_mut().expect("Use after finish");
let mut prefix = prefix.into();
if !prefix.starts_with('/') {
prefix.insert(0, '/')
}
parts.prefix = prefix;
}
self
}
/// Configure resource for specific path.
///
/// Resource may have variable path also. For instance, a resource with
@ -128,7 +168,7 @@ impl<S> Application<S> where S: 'static {
/// use actix_web::*;
///
/// fn main() {
/// let app = Application::new("/")
/// let app = Application::new()
/// .resource("/test", |r| {
/// r.method(Method::GET).f(|_| httpcodes::HTTPOk);
/// r.method(Method::HEAD).f(|_| httpcodes::HTTPMethodNotAllowed);
@ -184,7 +224,7 @@ impl<S> Application<S> where S: 'static {
/// }
///
/// fn main() {
/// let app = Application::new("/")
/// let app = Application::new()
/// .resource("/index.html", |r| r.f(index))
/// .external_resource("youtube", "https://youtube.com/watch/{video_id}")
/// .finish();
@ -275,7 +315,7 @@ mod tests {
#[test]
fn test_default_resource() {
let app = Application::new("/")
let app = Application::new()
.resource("/test", |r| r.h(httpcodes::HTTPOk))
.finish();
@ -291,7 +331,7 @@ mod tests {
let resp = app.run(req);
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
let app = Application::new("/")
let app = Application::new()
.default_resource(|r| r.h(httpcodes::HTTPMethodNotAllowed))
.finish();
let req = HttpRequest::new(
@ -303,7 +343,8 @@ mod tests {
#[test]
fn test_unhandled_prefix() {
let app = Application::new("/test")
let app = Application::new()
.prefix("/test")
.resource("/test", |r| r.h(httpcodes::HTTPOk))
.finish();
assert!(app.handle(HttpRequest::default()).is_err());
@ -311,7 +352,7 @@ mod tests {
#[test]
fn test_state() {
let app = Application::with_state("/", 10)
let app = Application::with_state(10)
.resource("/", |r| r.h(httpcodes::HTTPOk))
.finish();
let req = HttpRequest::default().with_state(Rc::clone(&app.state), app.router.clone());

View File

@ -199,7 +199,7 @@ impl FromRequest for FilesystemElement {
/// use actix_web::{fs, Application};
///
/// fn main() {
/// let app = Application::new("/")
/// let app = Application::new()
/// .resource("/static/{tail:.*}", |r| r.h(fs::StaticFiles::new("tail", ".", true)))
/// .finish();
/// }

View File

@ -303,7 +303,7 @@ impl<T: Serialize> FromRequest for Json<T> {
/// # httpcodes::HTTPOk
/// # }
/// fn main() {
/// let app = Application::new("/")
/// let app = Application::new()
/// .resource("/test/", |r| r.f(index))
/// .default_resource(|r| r.h(NormalizePath::default()))
/// .finish();
@ -412,7 +412,7 @@ mod tests {
#[test]
fn test_normalize_path_trailing_slashes() {
let app = Application::new("/")
let app = Application::new()
.resource("/resource1", |r| r.method(Method::GET).f(index))
.resource("/resource2/", |r| r.method(Method::GET).f(index))
.default_resource(|r| r.h(NormalizePath::default()))
@ -444,7 +444,7 @@ mod tests {
#[test]
fn test_normalize_path_trailing_slashes_disabled() {
let app = Application::new("/")
let app = Application::new()
.resource("/resource1", |r| r.method(Method::GET).f(index))
.resource("/resource2/", |r| r.method(Method::GET).f(index))
.default_resource(|r| r.h(
@ -471,7 +471,7 @@ mod tests {
#[test]
fn test_normalize_path_merge_slashes() {
let app = Application::new("/")
let app = Application::new()
.resource("/resource1", |r| r.method(Method::GET).f(index))
.resource("/resource1/a/b", |r| r.method(Method::GET).f(index))
.default_resource(|r| r.h(NormalizePath::default()))
@ -507,7 +507,7 @@ mod tests {
#[test]
fn test_normalize_path_merge_and_append_slashes() {
let app = Application::new("/")
let app = Application::new()
.resource("/resource1", |r| r.method(Method::GET).f(index))
.resource("/resource2/", |r| r.method(Method::GET).f(index))
.resource("/resource1/a/b", |r| r.method(Method::GET).f(index))

View File

@ -21,6 +21,7 @@ pub struct ConnectionInfo<'a> {
impl<'a> ConnectionInfo<'a> {
/// Create *ConnectionInfo* instance for a request.
#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
pub fn new<S>(req: &'a HttpRequest<S>) -> ConnectionInfo<'a> {
let mut host = None;
let mut scheme = None;

View File

@ -15,7 +15,7 @@ use middlewares::{Response, Middleware};
/// use actix_web::*;
///
/// fn main() {
/// let app = Application::new("/")
/// let app = Application::new()
/// .middleware(
/// middlewares::DefaultHeaders::build()
/// .header("X-Version", "0.2")

View File

@ -27,7 +27,7 @@ use middlewares::{Middleware, Started, Finished};
/// use actix_web::middlewares::Logger;
///
/// fn main() {
/// let app = Application::new("/")
/// let app = Application::new()
/// .middleware(Logger::default())
/// .middleware(Logger::new("%a %{User-Agent}i"))
/// .finish();

View File

@ -170,7 +170,7 @@ mod tests {
let pred = Header("transfer-encoding", "other");
assert!(!pred.check(&mut req));
let pred = Header("content-tye", "other");
let pred = Header("content-type", "other");
assert!(!pred.check(&mut req));
}

View File

@ -2,8 +2,9 @@ use std::marker::PhantomData;
use http::Method;
use pred;
use route::Route;
use handler::{Reply, Handler, FromRequest, RouteHandler, WrapHandler};
use handler::{Reply, Handler, FromRequest, RouteHandler};
use httpcodes::HTTPNotFound;
use httprequest::HttpRequest;
@ -22,7 +23,7 @@ use httprequest::HttpRequest;
/// use actix_web::*;
///
/// fn main() {
/// let app = Application::new("/")
/// let app = Application::new()
/// .resource(
/// "/", |r| r.method(Method::GET).f(|r| HttpResponse::Ok()))
/// .finish();
@ -31,7 +32,6 @@ pub struct Resource<S=()> {
name: String,
state: PhantomData<S>,
routes: Vec<Route<S>>,
default: Box<RouteHandler<S>>,
}
impl<S> Default for Resource<S> {
@ -39,8 +39,7 @@ impl<S> Default for Resource<S> {
Resource {
name: String::new(),
state: PhantomData,
routes: Vec::new(),
default: Box::new(HTTPNotFound)}
routes: Vec::new() }
}
}
@ -50,8 +49,7 @@ impl<S> Resource<S> {
Resource {
name: String::new(),
state: PhantomData,
routes: Vec::new(),
default: Box::new(HTTPNotFound)}
routes: Vec::new() }
}
/// Set resource name
@ -74,7 +72,7 @@ impl<S: 'static> Resource<S> {
/// use actix_web::*;
///
/// fn main() {
/// let app = Application::new("/")
/// let app = Application::new()
/// .resource(
/// "/", |r| r.route()
/// .p(pred::Any(vec![pred::Get(), pred::Put()]))
@ -97,7 +95,7 @@ impl<S: 'static> Resource<S> {
/// ```
pub fn method(&mut self, method: Method) -> &mut Route<S> {
self.routes.push(Route::default());
self.routes.last_mut().unwrap().method(method)
self.routes.last_mut().unwrap().p(pred::Method(method))
}
/// Register a new route and add handler object.
@ -126,12 +124,6 @@ impl<S: 'static> Resource<S> {
self.routes.push(Route::default());
self.routes.last_mut().unwrap().f(handler)
}
/// Default handler is used if no matched route found.
/// By default `HTTPNotFound` is used.
pub fn default_handler<H>(&mut self, handler: H) where H: Handler<S> {
self.default = Box::new(WrapHandler::new(handler));
}
}
impl<S: 'static> RouteHandler<S> for Resource<S> {
@ -142,6 +134,6 @@ impl<S: 'static> RouteHandler<S> for Resource<S> {
return route.handle(req)
}
}
self.default.handle(req)
Reply::response(HTTPNotFound)
}
}

View File

@ -1,8 +1,7 @@
use http::Method;
use futures::Future;
use error::Error;
use pred::{self, Predicate};
use pred::Predicate;
use handler::{Reply, Handler, FromRequest, RouteHandler, AsyncHandler, WrapHandler};
use httpcodes::HTTPNotFound;
use httprequest::HttpRequest;
@ -43,20 +42,6 @@ impl<S: 'static> Route<S> {
self.handler.handle(req)
}
/// Add method check to route. This method could be called multiple times.
pub fn method(&mut self, method: Method) -> &mut Self {
self.preds.push(pred::Method(method));
self
}
/// Add predicates to route.
pub fn predicates<P>(&mut self, preds: P) -> &mut Self
where P: IntoIterator<Item=Box<Predicate<S>>>
{
self.preds.extend(preds.into_iter());
self
}
/// Add match predicate to route.
pub fn p(&mut self, p: Box<Predicate<S>>) -> &mut Self {
self.preds.push(p);

View File

@ -42,7 +42,7 @@
//! }
//!
//! fn main() {
//! Application::new("/")
//! Application::new()
//! .resource("/ws/", |r| r.method(Method::GET).f(ws_index)) // <- register websocket route
//! .finish();
//! }