vamo_macros/
lib.rs

1//! # Vamo Macros
2//!
3//! This crate provides procedural macros for the `vamo` HTTP client, which is a higher-level
4//! abstraction over `deboa`. It includes a derive macro for automatically implementing the `Resource`
5//! trait, making it easy to work with RESTful resources.
6//!
7//! ## Features
8//!
9//! - **Resource Derive Macro**: Automatically implement RESTful operations for your types
10//! - **Attribute-based Configuration**: Configure resource endpoints using attributes
11//! - **Type-safe Serialization**: Seamless integration with serde for request/response bodies
12//! - **Async Support**: Built for async/await workflows
13//!
14//! ## Usage
15//!
16//! Add this to your `Cargo.toml`:
17//!
18//! ```toml
19//! [dependencies]
20//! vamo-macros = { path = "../vamo-macros" }
21//! vamo = { path = "../vamo" }
22//! deboa-extras = { path = "../deboa-extras" }
23//! serde = { version = "1.0", features = ["derive"] }
24//! ```
25//!
26//! ## Examples
27//!
28//! ### Basic Resource
29//!
30//! ```compile_fail
31//! use serde::{Deserialize, Serialize};
32//! use vamo_macros::Resource;
33//! use deboa_extras::http::serde::json::JsonBody;
34//!
35//! #[derive(Debug, Serialize, Deserialize, Resource)]
36//! #[name("posts")]
37//! #[body_type(JsonBody)]
38//! struct Post {
39//!     #[rid]
40//!     id: Option<u64>,
41//!     title: String,
42//!     body: String,
43//!     user_id: u64,
44//! }
45//!
46//! #[tokio::main]
47//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
48//!     let mut vamo = vamo::Vamo::new("https://jsonplaceholder.typicode.com")?;
49//!
50//!     // Create a new post
51//!     let new_post = Post {
52//!         id: None,
53//!         title: "Hello World".into(),
54//!         body: "This is a test post".into(),
55//!         user_id: 1,
56//!     };
57//!     let created: Post = vamo.create(&new_post).await?;
58//!     println!("Created post with ID: {}", created.id.unwrap());
59//!
60//!     Ok(())
61//! }
62//! ```
63//!
64//! ## Available Attributes
65//!
66//! ### Struct Attributes
67//!
68//! - `#[name("path")]`: Specify the resource name, rest endpoint (e.g., `posts`, `users`)
69//! - `#[body_type(Type)]`: Specify the request/response body type (e.g., `JsonBody`, `XmlBody`)
70//!
71//! ### Field Attributes
72//!
73//! - `#[rid]`: Mark a field as the resource identifier (must be `Option<T>` where T is a primitive type)
74//!
75//! ## Note
76//!
77//! The `Resource` derive macro automatically implements the following methods:
78//! - `new(base_path, vamo)`: Create a new resource client
79//! - `id()`: Get the resource identifier
80//! - `name()`: Get the resource name
81//! - `body_type()`: Get the resource body type
82
83use proc_macro::TokenStream;
84
85extern crate proc_macro;
86
87mod bora;
88mod resource;
89
90use crate::bora::bora as bora_macro;
91use crate::resource::resource as resource_macro;
92
93#[proc_macro_attribute]
94///
95/// The `bora` attribute macro is used to generate a Deboa client.
96/// With this macro you can define the API endpoints and their methods.
97/// You can define multiple endpoints and methods in the same macro.
98///
99/// A basic definition is:
100///
101/// #[bora(api(operation)))]
102///
103/// Where 'operation' is one or more of the following:
104///
105/// - get
106/// - post
107/// - delete
108/// - put
109/// - patch
110///
111/// # get
112///
113/// The `get` operation is used to retrieve data from the API.
114///
115/// It has the following arguments:
116///
117/// - name: The name of the operation.
118/// - path: The path of the operation.
119/// - res_body: The type of the response body.
120/// - format: The format of the response body.
121///
122/// ## Example
123///
124/// ```compile_fail
125/// #[bora(api(get(name = "get_post", path = "/posts/<id:i32>")))]
126/// pub struct PostService;
127/// ```
128///
129/// # post
130///
131/// The `post` operation is used to create data in the API.
132///
133/// It has the following arguments:
134///
135/// - name: The name of the operation.
136/// - path: The path of the operation.
137/// - req_body: The type of the request body.
138/// - res_body: The type of the response body.
139/// - format: The format of the response body.
140///
141/// ## Example
142///
143/// ```compile_fail
144/// #[bora(api(post(name = "post_post", path = "/posts", req_body = "Post", res_body = "Post")))]
145/// pub struct PostService;
146/// ```
147///
148/// # delete
149///
150/// The `delete` operation is used to delete data from the API.
151///
152/// It has the following arguments:
153///
154/// - name: The name of the operation.
155/// - path: The path of the operation.
156///
157/// ## Example
158///
159/// ```compile_fail
160/// #[bora(api(delete(name = "delete_post", path = "/posts/<id:i32>")))]
161/// pub struct PostService;
162/// ```
163///
164/// # put
165///
166/// The `put` operation is used to update data in the API.
167///
168/// It has the following arguments:
169///
170/// - name: The name of the operation.
171/// - path: The path of the operation.
172/// - req_body: The type of the request body.
173/// - res_body: The type of the response body.
174/// - format: The format of the response body.
175///
176/// ## Example
177///
178/// ```compile_fail
179/// #[bora(api(put(name = "put_post", path = "/posts/<id:i32>", req_body = "Post", res_body = "Post")))]
180/// pub struct PostService;
181/// ```
182///
183/// # patch
184///
185/// The `patch` operation is used to update data in the API.
186///
187/// It has the following arguments:
188///
189/// - name: The name of the operation.
190/// - path: The path of the operation.
191/// - req_body: The type of the request body.
192/// - res_body: The type of the response body.
193/// - format: The format of the response body.
194///
195/// ## Example
196///
197/// ```compile_fail
198/// #[bora(api(patch(name = "patch_post", path = "/posts/<id:i32>", req_body = "Post", res_body = "Post")))]
199/// pub struct PostService;
200/// ```
201pub fn bora(attr: TokenStream, item: TokenStream) -> TokenStream {
202    bora_macro(attr, item)
203}
204
205#[proc_macro_derive(Resource, attributes(rid, name, body_type))]
206/// Derive macro for the Resource trait.
207///
208/// # Attributes
209///
210/// * `rid` - The id of resource.
211/// * `name` - The name of resource.
212/// * `body_type` - The body type of resource (impl RequestBody from deboa-extras).
213///
214/// # Example
215///
216/// ```compile_fail
217/// use deboa_extras::http::serde::json::JsonBody;
218///
219/// #[derive(Resource)]
220/// #[name("posts")]
221/// #[body_type(JsonBody)]
222/// struct MyResource {
223///     #[rid("id")]
224///     id: String,
225/// }
226/// ```
227pub fn resource(input: TokenStream) -> TokenStream {
228    resource_macro(input)
229}