Skip to main content

actix_web_codegen/
lib.rs

1//! Routing and runtime macros for Actix Web.
2//!
3//! # Actix Web Re-exports
4//! Actix Web re-exports a version of this crate in it's entirety so you usually don't have to
5//! specify a dependency on this crate explicitly. Sometimes, however, updates are made to this
6//! crate before the actix-web dependency is updated. Therefore, code examples here will show
7//! explicit imports. Check the latest [actix-web attributes docs] to see which macros
8//! are re-exported.
9//!
10//! # Runtime Setup
11//! Used for setting up the actix async runtime. See [macro@main] macro docs.
12//!
13//! ```
14//! #[actix_web_codegen::main] // or `#[actix_web::main]` in Actix Web apps
15//! async fn main() {
16//!     async { println!("Hello world"); }.await
17//! }
18//! ```
19//!
20//! # Single Method Handler
21//! There is a macro to set up a handler for each of the most common HTTP methods that also define
22//! additional guards and route-specific middleware.
23//!
24//! See docs for: [GET], [POST], [PATCH], [PUT], [DELETE], [QUERY], [HEAD], [CONNECT], [OPTIONS],
25//! [TRACE]
26//!
27//! ```
28//! # use actix_web::HttpResponse;
29//! # use actix_web_codegen::get;
30//! #[get("/test")]
31//! async fn get_handler() -> HttpResponse {
32//!     HttpResponse::Ok().finish()
33//! }
34//! ```
35//!
36//! # Multiple Method Handlers
37//! Similar to the single method handler macro but takes one or more arguments for the HTTP methods
38//! it should respond to. See [macro@route] macro docs.
39//!
40//! ```
41//! # use actix_web::HttpResponse;
42//! # use actix_web_codegen::route;
43//! #[route("/test", method = "GET", method = "HEAD")]
44//! async fn get_and_head_handler() -> HttpResponse {
45//!     HttpResponse::Ok().finish()
46//! }
47//! ```
48//!
49//! # Multiple Path Handlers
50//! Acts as a wrapper for multiple single method handler macros. It takes no arguments and
51//! delegates those to the macros for the individual methods. See [macro@routes] macro docs.
52//!
53//! ```
54//! # use actix_web::HttpResponse;
55//! # use actix_web_codegen::routes;
56//! #[routes]
57//! #[get("/test")]
58//! #[get("/test2")]
59//! #[delete("/test")]
60//! async fn example() -> HttpResponse {
61//!     HttpResponse::Ok().finish()
62//! }
63//! ```
64//!
65//! [actix-web attributes docs]: https://docs.rs/actix-web/latest/actix_web/#attributes
66//! [CONNECT]: macro@macro@connect
67//! [DELETE]: macro@delete
68//! [GET]: macro@get
69//! [HEAD]: macro@head
70//! [OPTIONS]: macro@options
71//! [PATCH]: macro@patch
72//! [POST]: macro@post
73//! [PUT]: macro@put
74//! [QUERY]: macro@query
75//! [TRACE]: macro@trace
76
77#![recursion_limit = "512"]
78#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
79#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
80#![cfg_attr(docsrs, feature(doc_cfg))]
81
82use proc_macro::TokenStream;
83use quote::quote;
84
85mod route;
86mod scope;
87
88/// Creates resource handler, allowing multiple HTTP method guards.
89///
90/// # Syntax
91/// ```plain
92/// #[route("path", method="HTTP_METHOD"[, attributes])]
93/// ```
94///
95/// # Attributes
96/// - `"path"`: Raw literal string with path for which to register handler.
97/// - `name = "resource_name"`: Specifies resource name for the handler. If not set, the function
98///   name of handler is used.
99/// - `method = "HTTP_METHOD"`: Registers HTTP method to provide guard for. Upper-case string,
100///   "GET", "POST" for example.
101/// - `guard = "function_name"`: Registers function as guard using `actix_web::guard::fn_guard`.
102/// - `wrap = "Middleware"`: Registers a resource middleware.
103///
104/// # Notes
105/// Function name can be specified as any expression that is going to be accessible to the generate
106/// code, e.g `my_guard` or `my_module::my_guard`.
107///
108/// # Examples
109/// ```
110/// # use actix_web::HttpResponse;
111/// # use actix_web_codegen::route;
112/// #[route("/test", method = "GET", method = "HEAD", method = "CUSTOM")]
113/// async fn example() -> HttpResponse {
114///     HttpResponse::Ok().finish()
115/// }
116/// ```
117#[proc_macro_attribute]
118pub fn route(args: TokenStream, input: TokenStream) -> TokenStream {
119    route::with_method(None, args, input)
120}
121
122/// Creates resource handler, allowing multiple HTTP methods and paths.
123///
124/// # Syntax
125/// ```plain
126/// #[routes]
127/// #[<method>("path", ...)]
128/// #[<method>("path", ...)]
129/// ...
130/// ```
131///
132/// # Attributes
133/// The `routes` macro itself has no parameters, but allows specifying the attribute macros for
134/// the multiple paths and/or methods, e.g. [`GET`](macro@get) and [`POST`](macro@post).
135///
136/// These helper attributes take the same parameters as the [single method handlers](crate#single-method-handler).
137///
138/// # Examples
139/// ```
140/// # use actix_web::HttpResponse;
141/// # use actix_web_codegen::routes;
142/// #[routes]
143/// #[get("/test")]
144/// #[get("/test2")]
145/// #[delete("/test")]
146/// async fn example() -> HttpResponse {
147///     HttpResponse::Ok().finish()
148/// }
149/// ```
150#[proc_macro_attribute]
151pub fn routes(_: TokenStream, input: TokenStream) -> TokenStream {
152    route::with_methods(input)
153}
154
155macro_rules! method_macro {
156    ($variant:ident, $method:ident) => {
157        #[doc = concat!("Creates route handler with `actix_web::guard::", stringify!($variant), "`.")]
158        ///
159        /// # Syntax
160        /// ```plain
161        #[doc = concat!("#[", stringify!($method), r#"("path"[, attributes])]"#)]
162        /// ```
163        ///
164        /// # Attributes
165        /// - `"path"`: Raw literal string with path for which to register handler.
166        /// - `name = "resource_name"`: Specifies resource name for the handler. If not set, the
167        ///   function name of handler is used.
168        /// - `guard = "function_name"`: Registers function as guard using `actix_web::guard::fn_guard`.
169        /// - `wrap = "Middleware"`: Registers a resource middleware.
170        ///
171        /// # Notes
172        /// Function name can be specified as any expression that is going to be accessible to the
173        /// generate code, e.g `my_guard` or `my_module::my_guard`.
174        ///
175        /// # Examples
176        /// ```
177        /// # use actix_web::HttpResponse;
178        #[doc = concat!("# use actix_web_codegen::", stringify!($method), ";")]
179        #[doc = concat!("#[", stringify!($method), r#"("/")]"#)]
180        /// async fn example() -> HttpResponse {
181        ///     HttpResponse::Ok().finish()
182        /// }
183        /// ```
184        #[proc_macro_attribute]
185        pub fn $method(args: TokenStream, input: TokenStream) -> TokenStream {
186            route::with_method(Some(route::MethodType::$variant), args, input)
187        }
188    };
189}
190
191method_macro!(Connect, connect);
192method_macro!(Delete, delete);
193method_macro!(Get, get);
194method_macro!(Head, head);
195method_macro!(Options, options);
196method_macro!(Patch, patch);
197method_macro!(Post, post);
198method_macro!(Put, put);
199method_macro!(Query, query);
200method_macro!(Trace, trace);
201
202/// Prepends a path prefix to all handlers using routing macros inside the attached module.
203///
204/// # Syntax
205///
206/// ```
207/// # use actix_web_codegen::scope;
208/// #[scope("/prefix")]
209/// mod api {
210///     // ...
211/// }
212/// ```
213///
214/// # Arguments
215///
216/// - `"/prefix"` - Raw literal string to be prefixed onto contained handlers' paths.
217///
218/// # Example
219///
220/// ```
221/// # use actix_web_codegen::{scope, get};
222/// # use actix_web::Responder;
223/// #[scope("/api")]
224/// mod api {
225///     # use super::*;
226///     #[get("/hello")]
227///     pub async fn hello() -> impl Responder {
228///         // this has path /api/hello
229///         "Hello, world!"
230///     }
231/// }
232/// # fn main() {}
233/// ```
234#[proc_macro_attribute]
235pub fn scope(args: TokenStream, input: TokenStream) -> TokenStream {
236    scope::with_scope(args, input)
237}
238
239/// Marks async main function as the Actix Web system entry-point.
240///
241/// Note that Actix Web also works under `#[tokio::main]` since version 4.0. However, this macro is
242/// still necessary for actor support (since actors use a `System`). Read more in the
243/// [`actix_web::rt`](https://docs.rs/actix-web/4/actix_web/rt) module docs.
244///
245/// # Examples
246/// ```
247/// #[actix_web::main]
248/// async fn main() {
249///     async { println!("Hello world"); }.await
250/// }
251/// ```
252#[proc_macro_attribute]
253pub fn main(_: TokenStream, item: TokenStream) -> TokenStream {
254    let mut output: TokenStream = (quote! {
255        #[::actix_web::rt::main(system = "::actix_web::rt::System")]
256    })
257    .into();
258
259    output.extend(item);
260    output
261}
262
263/// Marks async test functions to use the Actix Web system entry-point.
264///
265/// # Examples
266/// ```
267/// #[actix_web::test]
268/// async fn test() {
269///     assert_eq!(async { "Hello world" }.await, "Hello world");
270/// }
271/// ```
272#[proc_macro_attribute]
273pub fn test(_: TokenStream, item: TokenStream) -> TokenStream {
274    let mut output: TokenStream = (quote! {
275        #[::actix_web::rt::test(system = "::actix_web::rt::System")]
276    })
277    .into();
278
279    output.extend(item);
280    output
281}
282
283/// Converts the error to a token stream and appends it to the original input.
284///
285/// Returning the original input in addition to the error is good for IDEs which can gracefully
286/// recover and show more precise errors within the macro body.
287///
288/// See <https://github.com/rust-analyzer/rust-analyzer/issues/10468> for more info.
289fn input_and_compile_error(mut item: TokenStream, err: syn::Error) -> TokenStream {
290    let compile_err = TokenStream::from(err.to_compile_error());
291    item.extend(compile_err);
292    item
293}