mirror of
https://github.com/actix/actix-web.git
synced 2024-11-14 04:41:15 +00:00
parent
34e5c7c799
commit
adf9935841
5 changed files with 109 additions and 117 deletions
|
@ -29,26 +29,25 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// # Pattern Format and Matching Behavior
|
/// # Pattern Format and Matching Behavior
|
||||||
///
|
|
||||||
/// Resource pattern is defined as a string of zero or more _segments_ where each segment is
|
/// Resource pattern is defined as a string of zero or more _segments_ where each segment is
|
||||||
/// preceded by a slash `/`.
|
/// preceded by a slash `/`.
|
||||||
///
|
///
|
||||||
/// This means that pattern string __must__ either be empty or begin with a slash (`/`).
|
/// This means that pattern string __must__ either be empty or begin with a slash (`/`). This also
|
||||||
/// This also implies that a trailing slash in pattern defines an empty segment.
|
/// implies that a trailing slash in pattern defines an empty segment. For example, the pattern
|
||||||
/// For example, the pattern `"/user/"` has two segments: `["user", ""]`
|
/// `"/user/"` has two segments: `["user", ""]`
|
||||||
///
|
///
|
||||||
/// A key point to underhand is that `ResourceDef` matches segments, not strings.
|
/// A key point to understand is that `ResourceDef` matches segments, not strings. Segments are
|
||||||
/// It matches segments individually.
|
/// matched individually. For example, the pattern `/user/` is not considered a prefix for the path
|
||||||
/// For example, the pattern `/user/` is not considered a prefix for the path `/user/123/456`,
|
/// `/user/123/456`, because the second segment doesn't match: `["user", ""]`
|
||||||
/// because the second segment doesn't match: `["user", ""]` vs `["user", "123", "456"]`.
|
/// vs `["user", "123", "456"]`.
|
||||||
///
|
///
|
||||||
/// This definition is consistent with the definition of absolute URL path in
|
/// This definition is consistent with the definition of absolute URL path in
|
||||||
/// [RFC 3986 (section 3.3)](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
|
/// [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// # Static Resources
|
/// # Static Resources
|
||||||
/// A static resource is the most basic type of definition. Pass a pattern to
|
/// A static resource is the most basic type of definition. Pass a pattern to [new][Self::new].
|
||||||
/// [new][Self::new]. Conforming paths must match the pattern exactly.
|
/// Conforming paths must match the pattern exactly.
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -63,7 +62,6 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
/// assert!(!resource.is_match("/search"));
|
/// assert!(!resource.is_match("/search"));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// # Dynamic Segments
|
/// # Dynamic Segments
|
||||||
/// Also known as "path parameters". Resources can define sections of a pattern that be extracted
|
/// Also known as "path parameters". Resources can define sections of a pattern that be extracted
|
||||||
/// from a conforming path, if it conforms to (one of) the resource pattern(s).
|
/// from a conforming path, if it conforms to (one of) the resource pattern(s).
|
||||||
|
@ -102,15 +100,15 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
/// assert_eq!(path.get("id").unwrap(), "123");
|
/// assert_eq!(path.get("id").unwrap(), "123");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// # Prefix Resources
|
/// # Prefix Resources
|
||||||
/// A prefix resource is defined as pattern that can match just the start of a path, up to a
|
/// A prefix resource is defined as pattern that can match just the start of a path, up to a
|
||||||
/// segment boundary.
|
/// segment boundary.
|
||||||
///
|
///
|
||||||
/// Prefix patterns with a trailing slash may have an unexpected, though correct, behavior.
|
/// Prefix patterns with a trailing slash may have an unexpected, though correct, behavior.
|
||||||
/// They define and therefore require an empty segment in order to match. Examples are given below.
|
/// They define and therefore require an empty segment in order to match. It is easier to understand
|
||||||
|
/// this behavior after reading the [matching behavior section]. Examples are given below.
|
||||||
///
|
///
|
||||||
/// Empty pattern matches any path as a prefix.
|
/// The empty pattern (`""`), as a prefix, matches any path.
|
||||||
///
|
///
|
||||||
/// Prefix resources can contain dynamic segments.
|
/// Prefix resources can contain dynamic segments.
|
||||||
///
|
///
|
||||||
|
@ -130,7 +128,6 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
/// assert!(!resource.is_match("/user/123"));
|
/// assert!(!resource.is_match("/user/123"));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// # Custom Regex Segments
|
/// # Custom Regex Segments
|
||||||
/// Dynamic segments can be customised to only match a specific regular expression. It can be
|
/// Dynamic segments can be customised to only match a specific regular expression. It can be
|
||||||
/// helpful to do this if resource definitions would otherwise conflict and cause one to
|
/// helpful to do this if resource definitions would otherwise conflict and cause one to
|
||||||
|
@ -158,7 +155,6 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
/// assert!(!resource.is_match("/user/abc"));
|
/// assert!(!resource.is_match("/user/abc"));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// # Tail Segments
|
/// # Tail Segments
|
||||||
/// As a shortcut to defining a custom regex for matching _all_ remaining characters (not just those
|
/// As a shortcut to defining a custom regex for matching _all_ remaining characters (not just those
|
||||||
/// up until a `/` character), there is a special pattern to match (and capture) the remaining
|
/// up until a `/` character), there is a special pattern to match (and capture) the remaining
|
||||||
|
@ -179,7 +175,6 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
/// assert_eq!(path.get("tail").unwrap(), "main/LICENSE");
|
/// assert_eq!(path.get("tail").unwrap(), "main/LICENSE");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// # Multi-Pattern Resources
|
/// # Multi-Pattern Resources
|
||||||
/// For resources that can map to multiple distinct paths, it may be suitable to use
|
/// For resources that can map to multiple distinct paths, it may be suitable to use
|
||||||
/// multi-pattern resources by passing an array/vec to [`new`][Self::new]. They will be combined
|
/// multi-pattern resources by passing an array/vec to [`new`][Self::new]. They will be combined
|
||||||
|
@ -198,7 +193,6 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
/// assert!(resource.is_match("/index"));
|
/// assert!(resource.is_match("/index"));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// # Trailing Slashes
|
/// # Trailing Slashes
|
||||||
/// It should be noted that this library takes no steps to normalize intra-path or trailing slashes.
|
/// It should be noted that this library takes no steps to normalize intra-path or trailing slashes.
|
||||||
/// As such, all resource definitions implicitly expect a pre-processing step to normalize paths if
|
/// As such, all resource definitions implicitly expect a pre-processing step to normalize paths if
|
||||||
|
@ -212,6 +206,8 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
/// assert!(!ResourceDef::new("/root/").is_match("/root"));
|
/// assert!(!ResourceDef::new("/root/").is_match("/root"));
|
||||||
/// assert!(!ResourceDef::prefix("/root/").is_match("/root"));
|
/// assert!(!ResourceDef::prefix("/root/").is_match("/root"));
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// [matching behavior section]: #pattern-format-and-matching-behavior
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ResourceDef {
|
pub struct ResourceDef {
|
||||||
id: u16,
|
id: u16,
|
||||||
|
@ -279,7 +275,7 @@ impl ResourceDef {
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new<T: IntoPatterns>(paths: T) -> Self {
|
pub fn new<T: IntoPatterns>(paths: T) -> Self {
|
||||||
profile_method!(new);
|
profile_method!(new);
|
||||||
Self::new2(paths, false)
|
Self::construct(paths, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new resource definition using a pattern that performs prefix matching.
|
/// Constructs a new resource definition using a pattern that performs prefix matching.
|
||||||
|
@ -292,7 +288,7 @@ impl ResourceDef {
|
||||||
/// resource definition with a tail segment; use [`new`][Self::new] in this case.
|
/// resource definition with a tail segment; use [`new`][Self::new] in this case.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if path regex pattern is malformed.
|
/// Panics if path pattern is malformed.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -307,14 +303,14 @@ impl ResourceDef {
|
||||||
/// ```
|
/// ```
|
||||||
pub fn prefix<T: IntoPatterns>(paths: T) -> Self {
|
pub fn prefix<T: IntoPatterns>(paths: T) -> Self {
|
||||||
profile_method!(prefix);
|
profile_method!(prefix);
|
||||||
ResourceDef::new2(paths, true)
|
ResourceDef::construct(paths, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new resource definition using a string pattern that performs prefix matching,
|
/// Constructs a new resource definition using a string pattern that performs prefix matching,
|
||||||
/// inserting a `/` to beginning of the pattern if absent and pattern is not empty.
|
/// ensuring a leading `/` if pattern is not empty.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if path regex pattern is malformed.
|
/// Panics if path pattern is malformed.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -515,8 +511,8 @@ impl ResourceDef {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
match patterns.len() {
|
match patterns.len() {
|
||||||
1 => ResourceDef::new2(&patterns[0], other.is_prefix()),
|
1 => ResourceDef::construct(&patterns[0], other.is_prefix()),
|
||||||
_ => ResourceDef::new2(patterns, other.is_prefix()),
|
_ => ResourceDef::construct(patterns, other.is_prefix()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,8 +877,8 @@ impl ResourceDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new2<T: IntoPatterns>(paths: T, is_prefix: bool) -> Self {
|
fn construct<T: IntoPatterns>(paths: T, is_prefix: bool) -> Self {
|
||||||
profile_method!(new2);
|
profile_method!(construct);
|
||||||
|
|
||||||
let patterns = paths.patterns();
|
let patterns = paths.patterns();
|
||||||
let (pat_type, segments) = match &patterns {
|
let (pat_type, segments) = match &patterns {
|
||||||
|
@ -1814,7 +1810,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn prefix_plus_tail_match_is_allowed() {
|
fn prefix_plus_tail_match_disallowed() {
|
||||||
ResourceDef::prefix("/user/{id}*");
|
ResourceDef::prefix("/user/{id}*");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,28 +23,25 @@ use crate::{
|
||||||
BoxError, Error, FromRequest, HttpResponse, Responder,
|
BoxError, Error, FromRequest, HttpResponse, Responder,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// *Resource* is an entry in resources table which corresponds to requested URL.
|
/// A collection of [`Route`]s that respond to the same path pattern.
|
||||||
///
|
///
|
||||||
/// Resource in turn has at least one route.
|
/// Resource in turn has at least one route. Route consists of an handlers objects and list of
|
||||||
/// Route consists of an handlers objects and list of guards
|
/// guards (objects that implement `Guard` trait). Resources and routes uses builder-like pattern
|
||||||
/// (objects that implement `Guard` trait).
|
/// for configuration. During request handling, resource object iterate through all routes and check
|
||||||
/// Resources and routes uses builder-like pattern for configuration.
|
/// guards for specific route, if request matches all guards, route considered matched and route
|
||||||
/// During request handling, resource object iterate through all routes
|
/// handler get called.
|
||||||
/// and check guards for specific route, if request matches all
|
|
||||||
/// guards, route considered matched and route handler get called.
|
|
||||||
///
|
///
|
||||||
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{web, App, HttpResponse};
|
/// use actix_web::{web, App, HttpResponse};
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// let app = App::new().service(
|
||||||
/// let app = App::new().service(
|
/// web::resource("/")
|
||||||
/// web::resource("/")
|
/// .route(web::get().to(|| HttpResponse::Ok())));
|
||||||
/// .route(web::get().to(|| HttpResponse::Ok())));
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// If no matching route could be found, *405* response code get returned.
|
/// If no matching route could be found, *405* response code get returned. Default behavior could be
|
||||||
/// Default behavior could be overridden with `default_resource()` method.
|
/// overridden with `default_resource()` method.
|
||||||
pub struct Resource<T = ResourceEndpoint, B = BoxBody> {
|
pub struct Resource<T = ResourceEndpoint, B = BoxBody> {
|
||||||
endpoint: T,
|
endpoint: T,
|
||||||
rdef: Patterns,
|
rdef: Patterns,
|
||||||
|
|
|
@ -15,10 +15,10 @@ use crate::{
|
||||||
BoxError, Error, FromRequest, HttpResponse, Responder,
|
BoxError, Error, FromRequest, HttpResponse, Responder,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Resource route definition
|
/// A request handler with [guards](guard).
|
||||||
///
|
///
|
||||||
/// Route uses builder-like pattern for configuration.
|
/// Route uses a builder-like pattern for configuration. If handler is not set, a `404 Not Found`
|
||||||
/// If handler is not explicitly set, default *404 Not Found* handler is used.
|
/// handler is used.
|
||||||
pub struct Route {
|
pub struct Route {
|
||||||
service: BoxedHttpServiceFactory,
|
service: BoxedHttpServiceFactory,
|
||||||
guards: Rc<Vec<Box<dyn Guard>>>,
|
guards: Rc<Vec<Box<dyn Guard>>>,
|
||||||
|
|
126
src/scope.rs
126
src/scope.rs
|
@ -27,34 +27,36 @@ use crate::{
|
||||||
|
|
||||||
type Guards = Vec<Box<dyn Guard>>;
|
type Guards = Vec<Box<dyn Guard>>;
|
||||||
|
|
||||||
/// Resources scope.
|
/// A collection of [`Route`]s, [`Resource`]s, or other services that share a common path prefix.
|
||||||
///
|
///
|
||||||
/// Scope is a set of resources with common root path.
|
/// The `Scope`'s path can contain [dynamic segments]. The dynamic segments can be extracted from
|
||||||
/// Scopes collect multiple paths under a common path prefix.
|
/// requests using the [`Path`](crate::web::Path) extractor or
|
||||||
/// Scope path can contain variable path segments as resources.
|
/// with [`HttpRequest::match_info()`](crate::HttpRequest::match_info).
|
||||||
/// Scope prefix is always complete path segment, i.e `/app` would
|
|
||||||
/// be converted to a `/app/` and it would not match `/app` path.
|
|
||||||
///
|
///
|
||||||
/// You can get variable path segments from `HttpRequest::match_info()`.
|
/// # Avoid Trailing Slashes
|
||||||
/// `Path` extractor also is able to extract scope level variable segments.
|
/// Avoid using trailing slashes in the scope prefix (e.g., `web::scope("/scope/")`). It will almost
|
||||||
|
/// certainly not have the expected behavior. See the [documentation on resource definitions][pat]
|
||||||
|
/// to understand why this is the case and how to correctly construct scope/prefix definitions.
|
||||||
///
|
///
|
||||||
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{web, App, HttpResponse};
|
/// use actix_web::{web, App, HttpResponse};
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// let app = App::new().service(
|
||||||
/// let app = App::new().service(
|
/// web::scope("/{project_id}/")
|
||||||
/// web::scope("/{project_id}/")
|
/// .service(web::resource("/path1").to(|| async { "OK" }))
|
||||||
/// .service(web::resource("/path1").to(|| async { "OK" }))
|
/// .service(web::resource("/path2").route(web::get().to(|| HttpResponse::Ok())))
|
||||||
/// .service(web::resource("/path2").route(web::get().to(|| HttpResponse::Ok())))
|
/// .service(web::resource("/path3").route(web::head().to(HttpResponse::MethodNotAllowed)))
|
||||||
/// .service(web::resource("/path3").route(web::head().to(HttpResponse::MethodNotAllowed)))
|
/// );
|
||||||
/// );
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// In the above example three routes get registered:
|
/// In the above example three routes get registered:
|
||||||
/// * /{project_id}/path1 - responds to all http method
|
/// - /{project_id}/path1 - responds to all HTTP methods
|
||||||
/// * /{project_id}/path2 - `GET` requests
|
/// - /{project_id}/path2 - responds to `GET` requests
|
||||||
/// * /{project_id}/path3 - `HEAD` requests
|
/// - /{project_id}/path3 - responds to `HEAD` requests
|
||||||
|
///
|
||||||
|
/// [pat]: crate::dev::ResourceDef#prefix-resources
|
||||||
|
/// [dynamic segments]: crate::dev::ResourceDef#dynamic-segments
|
||||||
pub struct Scope<T = ScopeEndpoint, B = BoxBody> {
|
pub struct Scope<T = ScopeEndpoint, B = BoxBody> {
|
||||||
endpoint: T,
|
endpoint: T,
|
||||||
rdef: String,
|
rdef: String,
|
||||||
|
@ -106,16 +108,14 @@ where
|
||||||
/// "Welcome!"
|
/// "Welcome!"
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// let app = App::new().service(
|
||||||
/// let app = App::new().service(
|
/// web::scope("/app")
|
||||||
/// web::scope("/app")
|
/// .guard(guard::Header("content-type", "text/plain"))
|
||||||
/// .guard(guard::Header("content-type", "text/plain"))
|
/// .route("/test1", web::get().to(index))
|
||||||
/// .route("/test1", web::get().to(index))
|
/// .route("/test2", web::post().to(|r: HttpRequest| {
|
||||||
/// .route("/test2", web::post().to(|r: HttpRequest| {
|
/// HttpResponse::MethodNotAllowed()
|
||||||
/// HttpResponse::MethodNotAllowed()
|
/// }))
|
||||||
/// }))
|
/// );
|
||||||
/// );
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn guard<G: Guard + 'static>(mut self, guard: G) -> Self {
|
pub fn guard<G: Guard + 'static>(mut self, guard: G) -> Self {
|
||||||
self.guards.push(Box::new(guard));
|
self.guards.push(Box::new(guard));
|
||||||
|
@ -186,15 +186,13 @@ where
|
||||||
/// );
|
/// );
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// let app = App::new()
|
||||||
/// let app = App::new()
|
/// .wrap(middleware::Logger::default())
|
||||||
/// .wrap(middleware::Logger::default())
|
/// .service(
|
||||||
/// .service(
|
/// web::scope("/api")
|
||||||
/// web::scope("/api")
|
/// .configure(config)
|
||||||
/// .configure(config)
|
/// )
|
||||||
/// )
|
/// .route("/index.html", web::get().to(|| HttpResponse::Ok()));
|
||||||
/// .route("/index.html", web::get().to(|| HttpResponse::Ok()));
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn configure<F>(mut self, cfg_fn: F) -> Self
|
pub fn configure<F>(mut self, cfg_fn: F) -> Self
|
||||||
where
|
where
|
||||||
|
@ -233,13 +231,11 @@ where
|
||||||
/// "Welcome!"
|
/// "Welcome!"
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// let app = App::new().service(
|
||||||
/// let app = App::new().service(
|
/// web::scope("/app").service(
|
||||||
/// web::scope("/app").service(
|
/// web::scope("/v1")
|
||||||
/// web::scope("/v1")
|
/// .service(web::resource("/test1").to(index)))
|
||||||
/// .service(web::resource("/test1").to(index)))
|
/// );
|
||||||
/// );
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn service<F>(mut self, factory: F) -> Self
|
pub fn service<F>(mut self, factory: F) -> Self
|
||||||
where
|
where
|
||||||
|
@ -263,13 +259,11 @@ where
|
||||||
/// "Welcome!"
|
/// "Welcome!"
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// let app = App::new().service(
|
||||||
/// let app = App::new().service(
|
/// web::scope("/app")
|
||||||
/// web::scope("/app")
|
/// .route("/test1", web::get().to(index))
|
||||||
/// .route("/test1", web::get().to(index))
|
/// .route("/test2", web::post().to(|| HttpResponse::MethodNotAllowed()))
|
||||||
/// .route("/test2", web::post().to(|| HttpResponse::MethodNotAllowed()))
|
/// );
|
||||||
/// );
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn route(self, path: &str, mut route: Route) -> Self {
|
pub fn route(self, path: &str, mut route: Route) -> Self {
|
||||||
self.service(
|
self.service(
|
||||||
|
@ -355,21 +349,19 @@ where
|
||||||
/// "Welcome!"
|
/// "Welcome!"
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// let app = App::new().service(
|
||||||
/// let app = App::new().service(
|
/// web::scope("/app")
|
||||||
/// web::scope("/app")
|
/// .wrap_fn(|req, srv| {
|
||||||
/// .wrap_fn(|req, srv| {
|
/// let fut = srv.call(req);
|
||||||
/// let fut = srv.call(req);
|
/// async {
|
||||||
/// async {
|
/// let mut res = fut.await?;
|
||||||
/// let mut res = fut.await?;
|
/// res.headers_mut().insert(
|
||||||
/// res.headers_mut().insert(
|
/// CONTENT_TYPE, HeaderValue::from_static("text/plain"),
|
||||||
/// CONTENT_TYPE, HeaderValue::from_static("text/plain"),
|
/// );
|
||||||
/// );
|
/// Ok(res)
|
||||||
/// Ok(res)
|
/// }
|
||||||
/// }
|
/// })
|
||||||
/// })
|
/// .route("/index.html", web::get().to(index)));
|
||||||
/// .route("/index.html", web::get().to(index)));
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn wrap_fn<F, R, B1>(
|
pub fn wrap_fn<F, R, B1>(
|
||||||
self,
|
self,
|
||||||
|
|
13
src/web.rs
13
src/web.rs
|
@ -52,11 +52,16 @@ pub fn resource<T: IntoPatterns>(path: T) -> Resource {
|
||||||
/// Scopes collect multiple paths under a common path prefix. The scope's path can contain dynamic
|
/// Scopes collect multiple paths under a common path prefix. The scope's path can contain dynamic
|
||||||
/// path segments.
|
/// path segments.
|
||||||
///
|
///
|
||||||
|
/// # Avoid Trailing Slashes
|
||||||
|
/// Avoid using trailing slashes in the scope prefix (e.g., `web::scope("/scope/")`). It will almost
|
||||||
|
/// certainly not have the expected behavior. See the [documentation on resource definitions][pat]
|
||||||
|
/// to understand why this is the case and how to correctly construct scope/prefix definitions.
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// In this example, three routes are set up (and will handle any method):
|
/// In this example, three routes are set up (and will handle any method):
|
||||||
/// * `/{project_id}/path1`
|
/// - `/{project_id}/path1`
|
||||||
/// * `/{project_id}/path2`
|
/// - `/{project_id}/path2`
|
||||||
/// * `/{project_id}/path3`
|
/// - `/{project_id}/path3`
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{web, App, HttpResponse};
|
/// use actix_web::{web, App, HttpResponse};
|
||||||
|
@ -68,6 +73,8 @@ pub fn resource<T: IntoPatterns>(path: T) -> Resource {
|
||||||
/// .service(web::resource("/path3").to(|| HttpResponse::MethodNotAllowed()))
|
/// .service(web::resource("/path3").to(|| HttpResponse::MethodNotAllowed()))
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// [pat]: crate::dev::ResourceDef#prefix-resources
|
||||||
pub fn scope(path: &str) -> Scope {
|
pub fn scope(path: &str) -> Scope {
|
||||||
Scope::new(path)
|
Scope::new(path)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue