From 8a88765ef7d1cfd166b20e9168c37ef2ef912c1f Mon Sep 17 00:00:00 2001 From: Roland Fredenhagen Date: Sat, 30 Apr 2022 18:22:50 +0200 Subject: [PATCH] chore: changelog, docs, tests --- actix-web-codegen/CHANGES.md | 5 ++- actix-web-codegen/src/lib.rs | 43 ++++++++++++++++++- actix-web-codegen/tests/test_macro.rs | 25 ++++++++++- actix-web-codegen/tests/trybuild.rs | 2 + actix-web-codegen/tests/trybuild/routes-ok.rs | 23 ++++++++++ actix-web/src/lib.rs | 1 + 6 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 actix-web-codegen/tests/trybuild/routes-ok.rs diff --git a/actix-web-codegen/CHANGES.md b/actix-web-codegen/CHANGES.md index 8ee787c0a42..b999bfcabd0 100644 --- a/actix-web-codegen/CHANGES.md +++ b/actix-web-codegen/CHANGES.md @@ -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 diff --git a/actix-web-codegen/src/lib.rs b/actix-web-codegen/src/lib.rs index d7d0704f870..693d9d34304 100644 --- a/actix-web-codegen/src/lib.rs +++ b/actix-web-codegen/src/lib.rs @@ -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] +/// #[("path", ...)] +/// #[("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) diff --git a/actix-web-codegen/tests/test_macro.rs b/actix-web-codegen/tests/test_macro.rs index 769cf2bc3ed..1146fdcf83c 100644 --- a/actix-web-codegen/tests/test_macro.rs +++ b/actix-web-codegen/tests/test_macro.rs @@ -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()); diff --git a/actix-web-codegen/tests/trybuild.rs b/actix-web-codegen/tests/trybuild.rs index b2d9ce186c9..17ece57da3f 100644 --- a/actix-web-codegen/tests/trybuild.rs +++ b/actix-web-codegen/tests/trybuild.rs @@ -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"); diff --git a/actix-web-codegen/tests/trybuild/routes-ok.rs b/actix-web-codegen/tests/trybuild/routes-ok.rs new file mode 100644 index 00000000000..98b5e553e77 --- /dev/null +++ b/actix-web-codegen/tests/trybuild/routes-ok.rs @@ -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()); +} diff --git a/actix-web/src/lib.rs b/actix-web/src/lib.rs index 4eab24cece4..8d9e2dbcdbf 100644 --- a/actix-web/src/lib.rs +++ b/actix-web/src/lib.rs @@ -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);