chore: changelog, docs, tests

This commit is contained in:
Roland Fredenhagen 2022-04-30 18:22:50 +02:00
parent b962959b82
commit f73c5406cb
No known key found for this signature in database
GPG Key ID: 094AF99241035EB6
6 changed files with 95 additions and 4 deletions

View File

@ -1,6 +1,9 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
- Added `#[actix_web::routes]` macro to support multiple routes on one handler
[#2718]: https://github.com/actix/actix-web/pull/2718
## 4.0.0 - 2022-02-24

View File

@ -46,9 +46,20 @@
//! ```
//!
//! # Multiple Path Handlers
//! There are no macros to generate multi-path handlers. Let us know in [this issue].
//! Acts as a wrapper for multiple single method handler macros. It takes no arguments and
//! delegates those to the macros for the individual methods. See [macro@routes] macro docs.
//!
//! [this issue]: https://github.com/actix/actix-web/issues/1709
//! ```
//! # use actix_web::HttpResponse;
//! # use actix_web_codegen::routes;
//! #[routes]
//! #[get("/test")]
//! #[get("/test2")]
//! #[delete("/test")]
//! async fn example() -> HttpResponse {
//! HttpResponse::Ok().finish()
//! }
//! ```
//!
//! [actix-web attributes docs]: https://docs.rs/actix-web/latest/actix_web/#attributes
//! [GET]: macro@get
@ -104,6 +115,34 @@ pub fn route(args: TokenStream, input: TokenStream) -> TokenStream {
route::with_method(None, args, input)
}
/// Creates resource handler, allowing multiple HTTP methods and paths.
///
/// # Syntax
/// ```plain
/// #[routes]
/// #[<method>("path", ...)]
/// #[<method>("path", ...)]
/// ...
/// ```
///
/// # Attributes
/// The `routes` macro it self has no parameters, but allows specifying the attribute macros for
/// the different methods, e.g. [`GET`](macro@get) or [`POST`](macro@post).
///
/// These helper attributes take the same parameters as the [single method handlers](crate#single-method-handler).
///
/// # Examples
/// ```
/// # use actix_web::HttpResponse;
/// # use actix_web_codegen::routes;
/// #[routes]
/// #[get("/test")]
/// #[get("/test2")]
/// #[delete("/test")]
/// async fn example() -> HttpResponse {
/// HttpResponse::Ok().finish()
/// }
/// ```
#[proc_macro_attribute]
pub fn routes(_: TokenStream, input: TokenStream) -> TokenStream {
route::with_methods(input)

View File

@ -10,7 +10,9 @@ use actix_web::{
},
web, App, Error, HttpResponse, Responder,
};
use actix_web_codegen::{connect, delete, get, head, options, patch, post, put, route, trace};
use actix_web_codegen::{
connect, delete, get, head, options, patch, post, put, route, routes, trace,
};
use futures_core::future::LocalBoxFuture;
// Make sure that we can name function as 'config'
@ -89,6 +91,14 @@ async fn route_test() -> impl Responder {
HttpResponse::Ok()
}
#[routes]
#[get("/routes/test")]
#[get("/routes/test2")]
#[post("/routes/test")]
async fn routes_test() -> impl Responder {
HttpResponse::Ok()
}
#[get("/custom_resource_name", name = "custom")]
async fn custom_resource_name_test<'a>(req: actix_web::HttpRequest) -> impl Responder {
assert!(req.url_for_static("custom").is_ok());
@ -186,6 +196,7 @@ async fn test_body() {
.service(patch_test)
.service(test_handler)
.service(route_test)
.service(routes_test)
.service(custom_resource_name_test)
});
let request = srv.request(http::Method::GET, srv.url("/test"));
@ -242,6 +253,18 @@ async fn test_body() {
let response = request.send().await.unwrap();
assert!(!response.status().is_success());
let request = srv.request(http::Method::GET, srv.url("/routes/test"));
let response = request.send().await.unwrap();
assert!(response.status().is_success());
let request = srv.request(http::Method::GET, srv.url("/routes/test2"));
let response = request.send().await.unwrap();
assert!(response.status().is_success());
let request = srv.request(http::Method::POST, srv.url("/routes/test"));
let response = request.send().await.unwrap();
assert!(response.status().is_success());
let request = srv.request(http::Method::GET, srv.url("/custom_resource_name"));
let response = request.send().await.unwrap();
assert!(response.status().is_success());

View File

@ -12,6 +12,8 @@ fn compile_macros() {
t.compile_fail("tests/trybuild/route-unexpected-method-fail.rs");
t.compile_fail("tests/trybuild/route-malformed-path-fail.rs");
t.pass("tests/trybuild/routes-ok.rs");
t.pass("tests/trybuild/docstring-ok.rs");
t.pass("tests/trybuild/test-runtime.rs");

View File

@ -0,0 +1,23 @@
use actix_web_codegen::*;
#[routes]
#[get("/")]
#[post("/")]
async fn index() -> String {
"Hello World!".to_owned()
}
#[actix_web::main]
async fn main() {
use actix_web::App;
let srv = actix_test::start(|| App::new().service(index));
let request = srv.get("/");
let response = request.send().await.unwrap();
assert!(response.status().is_success());
let request = srv.post("/");
let response = request.send().await.unwrap();
assert!(response.status().is_success());
}

View File

@ -132,6 +132,7 @@ macro_rules! codegen_reexport {
codegen_reexport!(main);
codegen_reexport!(test);
codegen_reexport!(route);
codegen_reexport!(routes);
codegen_reexport!(head);
codegen_reexport!(get);
codegen_reexport!(post);