1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//! Modular handler crafting for Salvo web framework.
//!
//! This crate provides the `#[craft]` attribute macro that enables a more
//! ergonomic way to define handlers as methods on structs, allowing for
//! better code organization and state sharing.
//!
//! # Overview
//!
//! Instead of writing standalone handler functions, you can organize related
//! handlers as methods on a struct, with shared state accessible via `self`:
//!
//! ```
//! use salvo::oapi::extract::PathParam;
//! use salvo::prelude::*;
//! use salvo_craft::craft;
//!
//! #[derive(Clone, Debug)]
//! pub struct UserService {
//! prefix: &'static str,
//! }
//!
//! #[craft]
//! impl UserService {
//! #[craft(handler)]
//! fn get_user(&self, id: PathParam<i64>) -> String {
//! format!("{} user {}", self.prefix, *id)
//! }
//!
//! #[craft(handler)]
//! fn list_users(&self) -> &'static str {
//! "listing users"
//! }
//! }
//!
//! let service = UserService { prefix: "hello" };
//! let _router = Router::new()
//! .push(Router::with_path("users").get(service.list_users()))
//! .push(Router::with_path("users/<id>").get(service.get_user()));
//! ```
//!
//! # Usage
//!
//! ## Basic Handler
//!
//! Use `#[craft(handler)]` to mark a method as a handler:
//!
//! ```
//! use salvo::prelude::*;
//! use salvo_craft::craft;
//!
//! #[derive(Clone, Debug)]
//! pub struct MyService;
//!
//! #[craft]
//! impl MyService {
//! #[craft(handler)]
//! fn hello(&self) -> &'static str {
//! "hello, world"
//! }
//! }
//!
//! let service = MyService;
//! let _router = Router::new().get(service.hello());
//! ```
//!
//! ## With OpenAPI Support
//!
//! Use `#[craft(endpoint(...))]` for handlers that should be included in
//! OpenAPI documentation:
//!
//! ```
//! use salvo::oapi::OpenApi;
//! use salvo::oapi::extract::QueryParam;
//! use salvo::prelude::*;
//! use salvo_craft::craft;
//!
//! #[derive(Clone, Debug)]
//! pub struct MyService;
//!
//! #[craft]
//! impl MyService {
//! #[craft(endpoint(tags("users"), status_codes(200, 404)))]
//! fn get_user(&self, id: QueryParam<i64>) -> String {
//! format!("user {}", *id)
//! }
//! }
//!
//! let service = MyService;
//! let router = Router::new().push(Router::with_path("users").get(service.get_user()));
//! let _doc = OpenApi::new("Craft Example", "0.1.0").merge_router(&router);
//! ```
//!
//! # Method Receivers
//!
//! The `#[craft]` macro supports different method receivers:
//!
//! | Receiver | Requirement | Use Case |
//! |----------|-------------|----------|
//! | `&self` | Type must implement `Clone` | Most common, shared state |
//! | `Arc<Self>` | None | Explicit reference counting |
//! | None (static) | None | Stateless handlers |
//!
//! ## Examples
//!
//! ```
//! use std::sync::Arc;
//!
//! use salvo::oapi::extract::QueryParam;
//! use salvo::prelude::*;
//! use salvo_craft::craft;
//!
//! #[derive(Clone, Debug)]
//! pub struct Service {
//! base: i64,
//! }
//!
//! #[craft]
//! impl Service {
//! #[craft(handler)]
//! fn with_ref(&self, value: QueryParam<i64>) -> String {
//! (self.base + *value).to_string()
//! }
//!
//! #[craft(handler)]
//! fn with_arc(self: Arc<Self>, value: QueryParam<i64>) -> String {
//! (self.base + *value).to_string()
//! }
//!
//! #[craft(handler)]
//! fn static_handler(value: QueryParam<i64>) -> String {
//! value.to_string()
//! }
//! }
//!
//! let service = Arc::new(Service { base: 1 });
//! let _router = Router::new()
//! .push(Router::with_path("with-ref").get(service.with_ref()))
//! .push(Router::with_path("with-arc").get(service.with_arc()))
//! .push(Router::with_path("static").get(Service::static_handler()));
//! ```
//!
//! # Router Integration
//!
//! Craft handlers are used with routers just like regular handlers:
//!
//! ```
//! use salvo::prelude::*;
//! use salvo_craft::craft;
//!
//! #[derive(Clone, Debug)]
//! pub struct UserService;
//!
//! #[craft]
//! impl UserService {
//! #[craft(handler)]
//! fn list_users(&self) -> &'static str {
//! "listing users"
//! }
//!
//! #[craft(handler)]
//! fn health() -> &'static str {
//! "ok"
//! }
//! }
//!
//! let service = UserService;
//! let router = Router::new()
//! .push(Router::with_path("users").get(service.list_users()))
//! .push(Router::with_path("health").get(UserService::health()));
//! let _ = router;
//! ```
//!
//! For a complete runnable example with OpenAPI integration, see
//! `crates/craft/examples/openapi.rs`.
pub use *;