rust_webx_macros/lib.rs
1// rust-webx-macros — Procedural macros for the Rust WebApi framework.
2// - #[endpoint(HttpMethod, "/path")] — full form
3// - #[get("/path")], #[post("/path")], #[put("/path")], #[delete("/path")] — shortcuts
4// - #[handler] — auto-registration via inventory
5// - #[FromBody], #[FromRoute], #[FromQuery] — parameter binding
6// - #[claims] — authentication claims injection
7// - #[authorize] — declarative authorization
8
9mod claims;
10mod endpoint;
11mod handler;
12mod request_meta;
13
14use proc_macro::TokenStream;
15
16// ---------------------------------------------------------------------------
17// Route macros: full form + shortcuts
18// ---------------------------------------------------------------------------
19
20/// Full form: marks an IRequest impl with HTTP method and route path.
21///
22/// ```ignore
23/// #[endpoint(HttpGet, "/users/{id}")]
24/// impl IRequest<UserModel> for GetUserRequest {}
25/// ```
26#[proc_macro_attribute]
27pub fn endpoint(attr: TokenStream, item: TokenStream) -> TokenStream {
28 endpoint::endpoint_impl(attr, item)
29}
30
31/// Shortcut: registers an IRequest impl at GET /path.
32///
33/// ```ignore
34/// #[get("/users/{id}")]
35/// impl IRequest<UserModel> for GetUserRequest {}
36/// ```
37#[proc_macro_attribute]
38pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
39 endpoint::shortcut_get(attr, item)
40}
41
42/// Shortcut: registers an IRequest impl at POST /path.
43///
44/// ```ignore
45/// #[post("/users")]
46/// impl IRequest<UserModel> for CreateUserRequest {}
47/// ```
48#[proc_macro_attribute]
49pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
50 endpoint::shortcut_post(attr, item)
51}
52
53/// Shortcut: registers an IRequest impl at PUT /path.
54///
55/// ```ignore
56/// #[put("/users/{id}")]
57/// impl IRequest<UserModel> for UpdateUserRequest {}
58/// ```
59#[proc_macro_attribute]
60pub fn put(attr: TokenStream, item: TokenStream) -> TokenStream {
61 endpoint::shortcut_put(attr, item)
62}
63
64/// Shortcut: registers an IRequest impl at DELETE /path.
65///
66/// ```ignore
67/// #[delete("/users/{id}")]
68/// impl IRequest<String> for DeleteUserRequest {}
69/// ```
70#[proc_macro_attribute]
71pub fn delete(attr: TokenStream, item: TokenStream) -> TokenStream {
72 endpoint::shortcut_delete(attr, item)
73}
74
75// ---------------------------------------------------------------------------
76// Handler auto-registration
77// ---------------------------------------------------------------------------
78
79/// Auto-registers an IRequestHandler implementation at compile time via inventory.
80///
81/// Place on `impl IRequestHandler<T, R> for Handler` blocks.
82/// The handler struct MUST implement `Default`.
83///
84/// ```ignore
85/// #[handler]
86/// #[async_trait]
87/// impl IRequestHandler<HelloRequest, String> for HelloHandler {
88/// async fn handle(&mut self, _req: HelloRequest) -> Result<String> { ... }
89/// }
90/// ```
91#[proc_macro_attribute]
92pub fn handler(attr: TokenStream, item: TokenStream) -> TokenStream {
93 handler::handler_impl(attr, item)
94}
95
96// ---------------------------------------------------------------------------
97// Parameter binding (OpenAPI metadata via WebxRequestMeta derive helpers)
98// ---------------------------------------------------------------------------
99//
100// `from_query`, `from_route`, and `from_body` are helper attributes for
101// `#[derive(WebxRequestMeta)]` — not standalone attribute macros (avoids
102// rustc conflicts on struct fields).
103
104/// Registers OpenAPI parameter metadata from `#[from_query]` / `#[from_route]` / `#[from_body]` fields.
105///
106/// Add `#[webx_request(query_all)]` to treat all non-skipped fields as query parameters.
107#[proc_macro_derive(WebxRequestMeta, attributes(from_query, from_route, from_body, webx_request))]
108pub fn webx_request_meta(input: TokenStream) -> TokenStream {
109 request_meta::derive_request_meta(input)
110}
111
112// ---------------------------------------------------------------------------
113// Declaration macros
114// ---------------------------------------------------------------------------
115
116// ---------------------------------------------------------------------------
117// Claims attribute
118// ---------------------------------------------------------------------------
119
120/// Marks a request struct as carrying authentication claims.
121///
122/// Appends a `#[serde(skip)] pub claims: Option<Box<dyn IClaims>>` field to
123/// the struct and generates an inherent `set_claims` method that shadows the
124/// blanket no-op `IClaimsCarrier::set_claims`. The dispatcher injects claims
125/// into the request *before* calling `IRequestHandler::handle`.
126///
127/// Must be the outermost attribute so that `#[derive(...)]` sees the injected
128/// field:
129///
130/// ```ignore
131/// #[claims]
132/// #[derive(Default, Deserialize)]
133/// pub struct CreateCommentRequest {
134/// pub blog_id: i32,
135/// pub content: String,
136/// }
137/// ```
138#[proc_macro_attribute]
139pub fn claims(attr: TokenStream, item: TokenStream) -> TokenStream {
140 claims::claims_impl(attr, item)
141}
142
143// ---------------------------------------------------------------------------
144// Authorization attribute (declarative, handled by emit_endpoint)
145// ---------------------------------------------------------------------------
146
147/// Declares authorization requirements on a route.
148///
149/// ```ignore
150/// #[get("/api/users")]
151/// #[authorize(role = "admin")]
152/// impl IRequest<Vec<UserModel>> for ListUsersRequest {}
153///
154/// #[get("/api/auth/me")]
155/// #[authorize]
156/// impl IRequest<UserView> for AuthMeRequest {}
157/// ```
158#[proc_macro_attribute]
159pub fn authorize(_attr: TokenStream, item: TokenStream) -> TokenStream {
160 // Pass through — the attribute is read by emit_endpoint inside
161 // the route macro (get, post, etc.) via item_impl.attrs.
162 item
163}