diff --git a/content/docs/url-dispatch.md b/content/docs/url-dispatch.md index 3a95dcb..0a0f5e3 100644 --- a/content/docs/url-dispatch.md +++ b/content/docs/url-dispatch.md @@ -10,9 +10,10 @@ URL dispatch provides a simple way for mapping URLs to handler code using a simp matching language. If one of the patterns matches the path information associated with a request, a particular handler object is invoked. -> A handler is a specific object that implements the `Handler` trait, defined in your -> application, that receives the request and returns a response object. More information -> is available in the [handler section][sec4handler]. +> A request handler is a function that accepts zero or more parameters that can be extracted +> from a request (ie, [*impl FromRequest*][implfromrequest]) and returns a type that can +> be converted into an HttpResponse (ie, [*impl Responder*][implresponder]). More information +> is available in the [handler section][handlersection]. # Resource configuration @@ -32,40 +33,33 @@ for the same path, in that case, multiple routes register for the same resource {{< include-example example="url-dispatch" section="main" >}} While *App::route()* provides simple way of registering routes, to access complete resource -configuration, a different method has to be used. The [*App::resource()*][appresource] method -adds a single resource to application routing table. This method accepts a *path pattern* -and a resource configuration function. +configuration, a different method has to be used. The [*App::service()*][appservice] method +adds a single [resource][webresource] to application routing table. This method accepts a +*path pattern*, guards, and one or more routes. {{< include-example example="url-dispatch" file="resource.rs" section="resource" >}} -The *Configuration function* has the following type: - -```rust -FnOnce(&mut Resource<_>) -> () -``` - -The *Configuration function* can set a name and register specific routes. If a resource does not contain any route or does not have any matching routes, it returns *NOT FOUND* http response. ## Configuring a Route -Resource contains a set of routes. Each route in turn has a set of predicates and a handler. +Resource contains a set of routes. Each route in turn has a set of `guards` and a handler. New routes can be created with `Resource::route()` method which returns a reference -to new *Route* instance. By default the *route* does not contain any predicates, so matches +to new *Route* instance. By default the *route* does not contain any guards, so matches all requests and the default handler is `HttpNotFound`. The application routes incoming requests based on route criteria which are defined during resource registration and route registration. Resource matches all routes it contains in the order the routes were registered via `Resource::route()`. -> A *Route* can contain any number of *predicates* but only one handler. +> A *Route* can contain any number of *guards* but only one handler. {{< include-example example="url-dispatch" file="cfg.rs" section="cfg" >}} -In this example, `HttpResponse::Ok()` is returned for *GET* requests. -If a request contains `Content-Type` header, the value of this header is *text/plain*, -and path equals to `/path`, Resource calls handle of the first matching route. +In this example, `HttpResponse::Ok()` is returned for *GET* requests if the request +contains `Content-Type` header, the value of this header is *text/plain*, and path +equals to `/path`. If a resource can not match any route, a "NOT FOUND" response is returned. @@ -77,19 +71,16 @@ can be configured with a builder-like pattern. Following configuration methods a * [*Route::method()*][routemethod] registers a method guard. Any number of guards can be registered for each route. * [*Route::to()*][routeto] registers handler function for this route. Only one handler - can be registered. Usually handler registration is the last config operation. Handler - function can be a function or closure and has the type `Fn(HttpRequest) -> R + 'static` + can be registered. Usually handler registration is the last config operation. * [*Route::to_async()*][routetoasync] registers an async handler function for this route. Only one handler can be registered. Handler registration is the last config operation. - Handler function can be a function or closure and has the type - `Fn(HttpRequest) -> Future + 'static` # Route matching The main purpose of route configuration is to match (or not match) the request's `path` against a URL path pattern. `path` represents the path portion of the URL that was requested. -The way that *actix* does this is very simple. When a request enters the system, +The way that *actix-web* does this is very simple. When a request enters the system, for each resource configuration declaration present in the system, actix checks the request's path against the pattern declared. This checking happens in the order that the routes were declared via `App::resource()` method. If resource can not be found, @@ -261,12 +252,12 @@ A *scoped* path can contain variable path segments as resources. Consistent with unscoped paths. You can get variable path segments from `HttpRequest::match_info()`. -`Path` extractor also is able to extract scope level variable segments. +[`Path` extractor][pathextractor] also is able to extract scope level variable segments. # Match information All values representing matched path segments are available in [`HttpRequest::match_info`][matchinfo]. -Specific values can be retrieved with [`Params::get()`][paramsget]. +Specific values can be retrieved with [`Path::get()`][pathget]. {{< include-example example="url-dispatch" file="minfo.rs" section="minfo" >}} @@ -339,16 +330,9 @@ normalization conditions, if all are enabled, is 1) merge, 2) both merge and app 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 doesn't have one, it will be appended automatically. - -If *merge* is *true*, merge multiple consecutive slashes in the path into one. - -This handler designed to be used as a handler for application's *default resource*. - {{< include-example example="url-dispatch" file="norm.rs" section="norm" >}} -In this example `/resource`, `//resource///` will be redirected to `/resource/`. +In this example `//resource///` will be redirected to `/resource/`. In this example, the path normalization handler is registered for all methods, but you should not rely on this mechanism to redirect *POST* requests. The redirect of the @@ -385,12 +369,12 @@ and returns *true* or *false*. Formally, a guard is any object that implements t Here is a simple guard that check that a request contains a specific *header*: -{{< include-example example="url-dispatch" file="pred.rs" section="pred" >}} +{{< include-example example="url-dispatch" file="guard.rs" section="guard" >}} In this example, *index* handler will be called only if request contains *CONTENT-TYPE* header. -Guards have access to the application's state via `HttpRequest::data()`. Also predicates -can store extra information in [request extensions][httprequest]. +Guards can not access or modify the request object, but it is possible to store extra +information in [request extensions][requestextensions]. ## Modifying guard values @@ -398,7 +382,7 @@ You can invert the meaning of any predicate value by wrapping it in a `Not` pred For example, if you want to return "METHOD NOT ALLOWED" response for all methods except "GET": -{{< include-example example="url-dispatch" file="pred2.rs" section="pred" >}} +{{< include-example example="url-dispatch" file="guard2.rs" section="guard2" >}} The `Any` guard accepts a list of guards and matches if any of the supplied guards match. i.e: @@ -424,21 +408,25 @@ with `App::service()` method. {{< include-example example="url-dispatch" file="dhandler.rs" section="default" >}} -[sec4handler]: sec-4-handler.html -[approute]: ../../actix-web/actix_web/struct.App.html#method.route -[appresource]: ../../actix-web/actix_web/struct.App.html#method.resource -[resourcehandler]: ../../actix-web/actix_web/dev/struct.ResourceHandler.html#method.route -[route]: ../../actix-web/actix_web/dev/struct.Route.html -[routeguard]: ../../actix-web/actix_web/dev/struct.Route.html#method.guard -[routemethod]: ../../actix-web/actix_web/dev/struct.Route.html#method.method -[routeto]: ../../actix-web/actix_web/dev/struct.Route.html#method.to -[routetoasync]: ../../actix-web/actix_web/dev/struct.Route.html#method.to_async -[matchinfo]: ../actix_web/struct.HttpRequest.html#method.match_info -[paramsget]: ../actix_web/dev/struct.Params.html#method.get -[pathstruct]: ../../actix-web/actix_web/struct.Path.html -[query]: ../../actix-web/actix_web/struct.Query.html -[urlfor]: ../../actix-web/actix_web/struct.HttpRequest.html#method.url_for -[urlobj]: https://docs.rs/url/1.7.0/url/struct.Url.html -[guardtrait]: ../actix_web/guard/trait.Guard.html -[guardfuncs]: ../../actix-web/actix_web/guard/index.html#functions -[httprequest]: ../../actix-web/actix_web/struct.HttpRequest.html#method.extensions +[handlersection]: ../handlers/ +[approute]: https://docs.rs/actix-web/1.0.2/actix_web/struct.App.html#method.route +[appservice]: https://docs.rs/actix-web/1.0.2/actix_web/struct.App.html?search=#method.service +[webresource]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Resource.html +[resourcehandler]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Resource.html#method.route +[route]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Route.html +[routeguard]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Route.html#method.guard +[routemethod]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Route.html#method.method +[routeto]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Route.html#method.to +[routetoasync]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Route.html#method.to_async +[matchinfo]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpRequest.html#method.match_info +[pathget]: https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.Path.html#method.get +[pathstruct]: https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.Path.html +[query]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Query.html +[urlfor]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpRequest.html#method.url_for +[urlobj]: https://docs.rs/url/1.7.2/url/struct.Url.html +[guardtrait]: https://docs.rs/actix-web/1.0.2/actix_web/guard/trait.Guard.html +[guardfuncs]: https://docs.rs/actix-web/1.0.2/actix_web/guard/index.html#functions +[requestextensions]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpRequest.html#method.extensions +[implfromrequest]: https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html +[implresponder]: https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html +[pathextractor]: ../extractors diff --git a/examples/url-dispatch/src/cfg.rs b/examples/url-dispatch/src/cfg.rs index de4de25..dfad2cd 100644 --- a/examples/url-dispatch/src/cfg.rs +++ b/examples/url-dispatch/src/cfg.rs @@ -1,14 +1,23 @@ -// use actix_web::{guard, web, App, HttpResponse}; +#[rustfmt::skip] pub fn main() { - App::new().service( - web::resource("/path").route( - web::route() - .guard(guard::Get()) - .guard(guard::Header("content-type", "text/plain")) - .to(|| HttpResponse::Ok()), - ), - ); -} + use actix_web::HttpServer; + + HttpServer::new(|| { +// +App::new().service( + web::resource("/path").route( + web::route() + .guard(guard::Get()) + .guard(guard::Header("content-type", "text/plain")) + .to(|| HttpResponse::Ok()), + ), +) // + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} diff --git a/examples/url-dispatch/src/dhandler.rs b/examples/url-dispatch/src/dhandler.rs index cb7a3db..e67891a 100644 --- a/examples/url-dispatch/src/dhandler.rs +++ b/examples/url-dispatch/src/dhandler.rs @@ -1,4 +1,4 @@ -use actix_web::{guard, web, App, HttpRequest, HttpResponse, Responder}; +use actix_web::{guard, web, App, HttpRequest, HttpResponse, HttpServer, Responder}; fn index(_req: HttpRequest) -> impl Responder { "Welcome!" @@ -6,12 +6,18 @@ fn index(_req: HttpRequest) -> impl Responder { // pub fn main() { - App::new() - .service(web::resource("/").route(web::get().to(index))) - .default_service( - web::route() - .guard(guard::Not(guard::Get())) - .to(|| HttpResponse::MethodNotAllowed()), - ); + HttpServer::new(|| { + App::new() + .service(web::resource("/").route(web::get().to(index))) + .default_service( + web::route() + .guard(guard::Not(guard::Get())) + .to(|| HttpResponse::MethodNotAllowed()), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/guard.rs b/examples/url-dispatch/src/guard.rs new file mode 100644 index 0000000..19bd514 --- /dev/null +++ b/examples/url-dispatch/src/guard.rs @@ -0,0 +1,28 @@ +// +use actix_web::{ + dev::RequestHead, guard::Guard, http, web, App, HttpResponse, HttpServer, +}; + +struct ContentTypeHeader; + +impl Guard for ContentTypeHeader { + fn check(&self, req: &RequestHead) -> bool { + req.headers().contains_key(http::header::CONTENT_TYPE) + } +} + +pub fn main() { + HttpServer::new(|| { + App::new().route( + "/", + web::route() + .guard(ContentTypeHeader) + .to(|| HttpResponse::Ok()), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// diff --git a/examples/url-dispatch/src/guard2.rs b/examples/url-dispatch/src/guard2.rs new file mode 100644 index 0000000..2d3d30b --- /dev/null +++ b/examples/url-dispatch/src/guard2.rs @@ -0,0 +1,18 @@ +// +use actix_web::{guard, web, App, HttpResponse, HttpServer}; + +pub fn main() { + HttpServer::new(|| { + App::new().route( + "/", + web::route() + .guard(guard::Not(guard::Get())) + .to(|| HttpResponse::MethodNotAllowed()), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// diff --git a/examples/url-dispatch/src/main.rs b/examples/url-dispatch/src/main.rs index bea247a..009b26a 100644 --- a/examples/url-dispatch/src/main.rs +++ b/examples/url-dispatch/src/main.rs @@ -1,28 +1,34 @@ pub mod cfg; pub mod dhandler; +pub mod guard; +pub mod guard2; pub mod minfo; pub mod norm; pub mod norm2; pub mod path; pub mod path2; pub mod pbuf; -pub mod pred; -pub mod pred2; pub mod resource; pub mod scope; pub mod url_ext; pub mod urls; //
-use actix_web::{web, App, HttpRequest, HttpResponse}; +use actix_web::{web, App, HttpResponse, HttpServer}; -fn index(_req: HttpRequest) -> HttpResponse { - unimplemented!() +fn index() -> HttpResponse { + HttpResponse::Ok().body("Hello") } fn main() { - App::new() - .route("/user/{name}", web::get().to(index)) - .route("/user/{name}", web::post().to(index)); + HttpServer::new(|| { + App::new() + .route("/", web::get().to(index)) + .route("/user", web::post().to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } //
diff --git a/examples/url-dispatch/src/minfo.rs b/examples/url-dispatch/src/minfo.rs index 2222945..920611a 100644 --- a/examples/url-dispatch/src/minfo.rs +++ b/examples/url-dispatch/src/minfo.rs @@ -9,8 +9,16 @@ fn index(req: HttpRequest) -> Result { } pub fn main() { - App::new() - .route("/a/{v1}/{v2}/", web::get().to(index)) - .route("", web::get().to(|| actix_web::HttpResponse::Ok())); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new() + .route("/a/{v1}/{v2}/", web::get().to(index)) + .route("", web::get().to(|| actix_web::HttpResponse::Ok())) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/norm.rs b/examples/url-dispatch/src/norm.rs index d396da4..75723d0 100644 --- a/examples/url-dispatch/src/norm.rs +++ b/examples/url-dispatch/src/norm.rs @@ -1,14 +1,21 @@ // -use actix_web::{middleware, web, App}; +use actix_web::{middleware, web, App, HttpResponse}; + +fn index() -> HttpResponse { + HttpResponse::Ok().body("Hello") +} pub fn main() { - App::new() - .wrap(middleware::NormalizePath) - .route("/", web::get().to(index)); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new() + .wrap(middleware::NormalizePath) + .route("/resource/", web::to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // - -use actix_web::HttpRequest; -fn index(_req: HttpRequest) -> String { - unimplemented!() -} diff --git a/examples/url-dispatch/src/norm2.rs b/examples/url-dispatch/src/norm2.rs index 1efc527..bd0f019 100644 --- a/examples/url-dispatch/src/norm2.rs +++ b/examples/url-dispatch/src/norm2.rs @@ -1,16 +1,22 @@ // -use actix_web::{http::Method, middleware, web, App}; +use actix_web::{http::Method, middleware, web, App, HttpServer}; pub fn main() { - App::new() - .wrap(middleware::NormalizePath) - .route("/resource/", web::get().to(index)) - .default_service(web::route().method(Method::GET)); + HttpServer::new(|| { + App::new() + .wrap(middleware::NormalizePath) + .route("/resource/", web::get().to(index)) + .default_service(web::route().method(Method::GET)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // -use actix_web::HttpRequest; +use actix_web::HttpResponse; -fn index(_req: HttpRequest) -> String { - unimplemented!() +fn index() -> HttpResponse { + HttpResponse::Ok().body("Hello") } diff --git a/examples/url-dispatch/src/path.rs b/examples/url-dispatch/src/path.rs index f3aea1a..1c84400 100644 --- a/examples/url-dispatch/src/path.rs +++ b/examples/url-dispatch/src/path.rs @@ -1,15 +1,22 @@ // use actix_web::{web, App, Result}; -// extract path info using serde fn index(info: web::Path<(String, u32)>) -> Result { Ok(format!("Welcome {}! id: {}", info.0, info.1)) } pub fn main() { - App::new().route( - "/{username}/{id}/index.html", // <- define path parameters - web::get().to(index), - ); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new().route( + "/{username}/{id}/index.html", // <- define path parameters + web::get().to(index), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/path2.rs b/examples/url-dispatch/src/path2.rs index 53d4532..783949f 100644 --- a/examples/url-dispatch/src/path2.rs +++ b/examples/url-dispatch/src/path2.rs @@ -13,9 +13,17 @@ fn index(info: web::Path) -> Result { } pub fn main() { - App::new().route( - "/{username}/index.html", // <- define path parameters - web::get().to(index), - ); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new().route( + "/{username}/index.html", // <- define path parameters + web::get().to(index), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/pbuf.rs b/examples/url-dispatch/src/pbuf.rs index 4ca0102..1319ad0 100644 --- a/examples/url-dispatch/src/pbuf.rs +++ b/examples/url-dispatch/src/pbuf.rs @@ -8,6 +8,12 @@ fn index(req: HttpRequest) -> Result { } pub fn main() { - App::new().route(r"/a/{tail:.*}", web::get().to(index)); + use actix_web::HttpServer; + + HttpServer::new(|| App::new().route(r"/a/{tail:.*}", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/pred.rs b/examples/url-dispatch/src/pred.rs deleted file mode 100644 index 2617fa2..0000000 --- a/examples/url-dispatch/src/pred.rs +++ /dev/null @@ -1,20 +0,0 @@ -// -use actix_web::{dev::RequestHead, guard::Guard, http, web, App, HttpResponse}; - -struct ContentTypeHeader; - -impl Guard for ContentTypeHeader { - fn check(&self, req: &RequestHead) -> bool { - req.headers().contains_key(http::header::CONTENT_TYPE) - } -} - -pub fn main() { - App::new().route( - "", - web::route() - .guard(ContentTypeHeader) - .to(|| HttpResponse::Ok()), - ); -} -// diff --git a/examples/url-dispatch/src/pred2.rs b/examples/url-dispatch/src/pred2.rs deleted file mode 100644 index 68d13d7..0000000 --- a/examples/url-dispatch/src/pred2.rs +++ /dev/null @@ -1,12 +0,0 @@ -// -use actix_web::{guard, web, App, HttpResponse}; - -pub fn main() { - App::new().route( - "/", - web::route() - .guard(guard::Not(guard::Get())) - .to(|| HttpResponse::MethodNotAllowed()), - ); -} -// diff --git a/examples/url-dispatch/src/resource.rs b/examples/url-dispatch/src/resource.rs index a231856..778a712 100644 --- a/examples/url-dispatch/src/resource.rs +++ b/examples/url-dispatch/src/resource.rs @@ -1,15 +1,19 @@ // -use actix_web::{web, App, HttpRequest, HttpResponse}; +use actix_web::{guard, web, App, HttpResponse}; -fn index(_req: HttpRequest) -> HttpResponse { - unimplemented!() +fn index() -> HttpResponse { + HttpResponse::Ok().body("Hello") } pub fn main() { App::new() .service(web::resource("/prefix").to(index)) .service( - web::resource("/user/{name}").route(web::get().to(|| HttpResponse::Ok())), + web::resource("/user/{name}") + .name("user_detail") + .guard(guard::Header("content-type", "application/json")) + .route(web::get().to(|| HttpResponse::Ok())) + .route(web::put().to(|| HttpResponse::Ok())), ); } // diff --git a/examples/url-dispatch/src/scope.rs b/examples/url-dispatch/src/scope.rs index 01795ef..388acef 100644 --- a/examples/url-dispatch/src/scope.rs +++ b/examples/url-dispatch/src/scope.rs @@ -1,11 +1,25 @@ -use actix_web::{web, App, HttpRequest, HttpResponse}; +use actix_web::{web, App, HttpResponse, HttpServer}; // -fn show_users(_req: HttpRequest) -> HttpResponse { - unimplemented!() +fn show_users() -> HttpResponse { + HttpResponse::Ok().body("Show users") +} + +fn user_detail(_path: web::Path<(u32,)>) -> HttpResponse { + HttpResponse::Ok().body("User detail") } pub fn main() { - App::new().service(web::scope("/users").route("/show", web::get().to(show_users))); + HttpServer::new(|| { + App::new().service( + web::scope("/users") + .route("/show", web::get().to(show_users)) + .route("/show/{id}", web::get().to(user_detail)), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/url_ext.rs b/examples/url-dispatch/src/url_ext.rs index 8f1869c..fafb66d 100644 --- a/examples/url-dispatch/src/url_ext.rs +++ b/examples/url-dispatch/src/url_ext.rs @@ -9,9 +9,17 @@ fn index(req: HttpRequest) -> impl Responder { } pub fn main() { - App::new() - .route("/index.html", web::get().to(index)) - .external_resource("youtube", "https://youtube.com/watch/{video_id}") - .route("/", actix_web::web::get().to(index)); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new() + .route("/", web::get().to(index)) + .external_resource("youtube", "https://youtube.com/watch/{video_id}") + .route("/", actix_web::web::get().to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/urls.rs b/examples/url-dispatch/src/urls.rs index 0ad653a..24cff65 100644 --- a/examples/url-dispatch/src/urls.rs +++ b/examples/url-dispatch/src/urls.rs @@ -3,19 +3,28 @@ use actix_web::{guard, http::header, web, App, HttpRequest, HttpResponse, Result fn index(req: HttpRequest) -> Result { let url = req.url_for("foo", &["1", "2", "3"])?; // <- generate url for "foo" resource + Ok(HttpResponse::Found() .header(header::LOCATION, url.as_str()) .finish()) } pub fn main() { - App::new() - .service( - web::resource("/test/{a}/{b}/{c}") - .name("foo") // <- set resource name, then it could be used in `url_for` - .guard(guard::Get()) - .to(|| HttpResponse::Ok()), - ) - .route("/test/", web::get().to(index)); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new() + .service( + web::resource("/test/{a}/{b}/{c}") + .name("foo") // <- set resource name, then it could be used in `url_for` + .guard(guard::Get()) + .to(|| HttpResponse::Ok()), + ) + .route("/test/", web::get().to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } //