1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 16:02:59 +01:00
actix-extras/guide/src/qs_5.md

248 lines
6.9 KiB
Markdown
Raw Normal View History

2017-12-02 08:42:21 +01:00
# Resources and Routes
All resources and routes register for specific application.
Application routes incoming requests based on route criteria which is defined during
resource registration or path prefix for simple handlers.
Internally *router* is a list of *resources*. Resource is an entry in *route table*
which corresponds to requested URL.
Prefix handler:
2017-12-04 22:32:05 +01:00
```rust
# extern crate actix_web;
# use actix_web::*;
2017-12-05 05:38:38 +01:00
#
2017-12-04 22:32:05 +01:00
fn index(req: HttpRequest) -> HttpResponse {
unimplemented!()
2017-12-02 08:42:21 +01:00
}
fn main() {
2017-12-06 20:00:39 +01:00
Application::new("/")
.resource("/prefix", |r| r.f(index))
2017-12-02 08:42:21 +01:00
.finish();
}
```
In this example `index` get called for any url which starts with `/prefix`.
Application prefix combines with handler prefix i.e
2017-12-04 22:32:05 +01:00
```rust
# extern crate actix_web;
# use actix_web::*;
2017-12-05 05:38:38 +01:00
#
2017-12-04 22:32:05 +01:00
fn index(req: HttpRequest) -> HttpResponse {
unimplemented!()
}
2017-12-02 08:42:21 +01:00
fn main() {
2017-12-06 20:00:39 +01:00
Application::new("/app")
.resource("/prefix", |r| r.f(index))
2017-12-02 08:42:21 +01:00
.finish();
}
```
In this example `index` get called for any url which starts with`/app/prefix`.
Resource contains set of route for same endpoint. Route corresponds to handling
*HTTP method* by calling *web handler*. Resource select route based on *http method*,
if no route could be matched default response `HTTPMethodNotAllowed` get resturned.
2017-12-04 22:32:05 +01:00
```rust
# extern crate actix_web;
# use actix_web::*;
2017-12-05 05:38:38 +01:00
#
2017-12-02 08:42:21 +01:00
fn main() {
2017-12-06 20:00:39 +01:00
Application::new("/")
2017-12-02 08:42:21 +01:00
.resource("/prefix", |r| {
r.method(Method::GET).h(httpcodes::HTTPOk);
r.method(Method::POST).h(httpcodes::HTTPForbidden);
2017-12-02 08:42:21 +01:00
})
.finish();
}
```
[`ApplicationBuilder::resource()` method](../actix_web/dev/struct.ApplicationBuilder.html#method.resource)
accepts configuration function, resource could be configured at once.
Check [`Resource`](../actix-web/target/doc/actix_web/struct.Resource.html) documentation
for more information.
## Variable resources
Resource may have *variable path*also. For instance, a resource with the
path '/a/{name}/c' would match all incoming requests with paths such
as '/a/b/c', '/a/1/c', and '/a/etc/c'.
A *variable part* is specified in the form {identifier}, where the identifier can be
2017-12-02 08:42:21 +01:00
used later in a request handler to access the matched value for that part. This is
done by looking up the identifier in the `HttpRequest.match_info` object:
```rust
2017-12-04 22:32:05 +01:00
# extern crate actix_web;
2017-12-02 08:42:21 +01:00
use actix_web::*;
fn index(req: HttpRequest) -> String {
format!("Hello, {}", &req.match_info()["name"])
2017-12-02 08:42:21 +01:00
}
fn main() {
2017-12-06 20:00:39 +01:00
Application::new("/")
.resource("/{name}", |r| r.method(Method::GET).f(index))
2017-12-02 08:42:21 +01:00
.finish();
}
```
By default, each part matches the regular expression `[^{}/]+`.
You can also specify a custom regex in the form `{identifier:regex}`:
2017-12-04 22:32:05 +01:00
```rust
# extern crate actix_web;
# use actix_web::*;
# fn index(req: HttpRequest) -> String {
# format!("Hello, {}", &req.match_info()["name"])
# }
2017-12-05 05:38:38 +01:00
#
2017-12-02 08:42:21 +01:00
fn main() {
2017-12-06 20:00:39 +01:00
Application::new("/")
.resource(r"{name:\d+}", |r| r.method(Method::GET).f(index))
2017-12-02 08:42:21 +01:00
.finish();
}
```
Any matched parameter can be deserialized into specific type if this type
implements `FromParam` trait. For example most of standard integer types
implements `FromParam` trait. i.e.:
```rust
2017-12-05 05:38:38 +01:00
# extern crate actix_web;
use actix_web::*;
fn index(req: HttpRequest) -> Result<String> {
let v1: u8 = req.match_info().query("v1")?;
let v2: u8 = req.match_info().query("v2")?;
Ok(format!("Values {} {}", v1, v2))
}
fn main() {
2017-12-06 20:00:39 +01:00
Application::new("/")
.resource(r"/a/{v1}/{v2}/", |r| r.f(index))
.finish();
}
```
For this example for path '/a/1/2/', values v1 and v2 will resolve to "1" and "2".
2017-12-04 22:32:05 +01:00
It is possible to match path tail with custom `.*` regex.
2017-12-02 08:42:21 +01:00
2017-12-05 05:38:38 +01:00
```rust
# extern crate actix_web;
# use actix_web::*;
#
# fn index(req: HttpRequest) -> HttpResponse {
# unimplemented!()
# }
2017-12-02 08:42:21 +01:00
fn main() {
2017-12-06 20:00:39 +01:00
Application::new("/")
.resource(r"/test/{tail:.*}", |r| r.method(Method::GET).f(index))
2017-12-02 08:42:21 +01:00
.finish();
}
```
Above example would match all incoming requests with path such as
'/test/b/c', '/test/index.html', and '/test/etc/test'.
It is possible to create a `PathBuf` from a tail path parameter. The returned `PathBuf` is
percent-decoded. If a segment is equal to "..", the previous segment (if
any) is skipped.
For security purposes, if a segment meets any of the following conditions,
an `Err` is returned indicating the condition met:
* Decoded segment starts with any of: `.` (except `..`), `*`
* Decoded segment ends with any of: `:`, `>`, `<`
* Decoded segment contains any of: `/`
* On Windows, decoded segment contains any of: '\'
* Percent-encoding results in invalid UTF8.
As a result of these conditions, a `PathBuf` parsed from request path parameter is
2017-12-04 22:32:05 +01:00
safe to interpolate within, or use as a suffix of, a path without additional checks.
```rust
2017-12-04 22:32:05 +01:00
# extern crate actix_web;
use actix_web::*;
use std::path::PathBuf;
fn index(req: HttpRequest) -> Result<String> {
let path: PathBuf = req.match_info().query("tail")?;
Ok(format!("Path {:?}", path))
}
fn main() {
2017-12-06 20:00:39 +01:00
Application::new("/")
.resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index))
.finish();
}
```
2017-12-09 22:58:24 +01:00
### Path normalization
By normalizing it means:
- Add a trailing slash to the path.
- Double slashes are replaced by one.
The handler returns as soon as it finds a path that resolves
correctly. The order if all enable is 1) merge, 3) both merge and append
and 3) append. If the path resolves with
at least one of those conditions, it will redirect to the new path.
If *append* is *true* append slash when needed. If a resource is
defined with trailing slash and the request comes without it, it will
append it automatically.
If *merge* is *true*, merge multiple consecutive slashes in the path into one.
This handler designed to be use as a handler for application's *default resource*.
```rust
# extern crate actix_web;
# #[macro_use] extern crate serde_derive;
# use actix_web::*;
#
# fn index(req: HttpRequest) -> httpcodes::StaticResponse {
# httpcodes::HTTPOk
# }
fn main() {
let app = Application::new("/")
.resource("/resource/", |r| r.f(index))
.default_resource(|r| r.h(NormalizePath::default()))
.finish();
}
```
In this example `/resource`, `//resource///` will be redirected to `/resource/` url.
2017-12-09 23:06:22 +01:00
In this example path normalization handler get registered for all method,
but you should not rely on this mechanism to redirect *POST* requests. The redirect of the
slash-appending *Not Found* will turn a *POST* request into a GET, losing any
*POST* data in the original request.
It is possible to register path normalization only for *GET* requests only
```rust
# extern crate actix_web;
# #[macro_use] extern crate serde_derive;
# use actix_web::*;
#
# fn index(req: HttpRequest) -> httpcodes::StaticResponse {
# httpcodes::HTTPOk
# }
fn main() {
let app = Application::new("/")
.resource("/resource/", |r| r.f(index))
.default_resource(|r| r.method(Method::GET).h(NormalizePath::default()))
.finish();
}
```