Skip to main content

esi_openapi/
macros.rs

1/// Create a function for calling a single endpoint
2/// with a GET request.
3///
4/// # Example
5/// ```rust,no_run
6/// # use esi_openapi::prelude::*;
7/// # use esi_openapi::api_get;
8/// pub struct SomeGroup<'a> {
9///     pub(crate) esi: &'a Esi,
10/// }
11///
12/// impl SomeGroup<'_> {
13///
14///     api_get!(
15///         /// Docs for the generated function
16///         function_name,
17///         "some_operation_id",
18///         RequestType::Public,
19///         Vec<u64>,
20///     );
21///
22/// }
23/// # fn main() {}
24/// ```
25///
26/// ## Result:
27///
28/// ```rust,ignore
29/// /// Docs for the generated function
30/// pub async fn function_name(&self) -> EsiResult<Vec<u64>> {
31///     let path = self.esi.get_endpoint_for_op_id("some_operation_id")?;
32///     self.esi
33///         .query("GET", RequestType::Public, &path, None, None)
34///         .await
35/// }
36/// ```
37///
38/// Additionally, this macro supports path replacements to insert variables
39/// into the path from ESI.
40///
41/// # Example
42///
43/// ```rust,no_run
44/// # use esi_openapi::prelude::*;
45/// # use esi_openapi::api_get;
46/// pub struct SomeGroup<'a> {
47///     pub(crate) esi: &'a Esi,
48/// }
49///
50/// impl SomeGroup<'_> {
51///
52///     api_get!(
53///         /// Docs for the generated function
54///         function_name,
55///         "some_operation_id",
56///         RequestType::Public,
57///         Vec<u64>,
58///         (alliance_id: u64) => "{alliance_id}"
59///     );
60///
61/// }
62/// # fn main() {}
63/// ```
64/// ## Result:
65///
66/// ```rust,ignore
67/// /// Docs for the generated function
68/// pub async fn function_name(&self, alliance_id: u64) -> EsiResult<Vec<u64>> {
69///     let path = self.esi.get_endpoint_for_op_id("some_operation_id")?
70///         .replace("{alliance_id}", &alliance_id.to_string());
71///     self.esi
72///         .query("GET", RequestType::Public, &path, None, None)
73///         .await
74/// }
75/// ```
76///
77/// Finally, there is support for required and optional query params. These are different from path
78/// parameters: in 'markets/{region_id}/orders?page=1', region_id is a path parameter and page is a
79/// query parameter. Note that in the macro invocation, query parameters are separated from path
80/// parameters with a semicolon, and that optional query parameters always follow required ones.
81/// See [crate::groups::MarketGroup] for sample macro calls.
82///
83/// # Example
84///
85/// ```rust,no_run
86/// # use esi_openapi::prelude::*;
87/// # use esi_openapi::api_get;
88/// pub struct SomeGroup<'a> {
89///     pub(crate) esi: &'a Esi,
90/// }
91///
92/// impl SomeGroup<'_> {
93///
94///     api_get!(
95///         /// Docs for the generated function
96///         function_name,
97///         "some_operation_id",
98///         RequestType::Public,
99///         Vec<u64>,
100///         (region_id: u64) => "{region_id}";
101///         (page: i32) => "page";
102///         Optional(order_type: bool) => "order_type"
103///     );
104///
105/// }
106/// # fn main() {}
107/// ```
108/// ## Result:
109///
110/// ```rust,ignore
111/// /// Docs for the generated function
112/// pub async fn function_name(&self, region_id: u64, page: i32, order_type: Option<bool>) -> EsiResult<Vec<u64>> {
113///     let path = self.esi.get_endpoint_for_op_id("some_operation_id")?
114///         .replace("{region_id}", &region_id.to_string());
115///     let params = vec![
116///         ("page", page.to_string()),
117///     ]
118///     let mut params = params;
119///     if let Some(order_type) = order_type {
120///         params.push(("order_type", order_type.to_string()))
121///     }
122///     let params: Vec<(&str, &str)> = params.iter().map(|(a, b)| (*a, &**b)).collect();
123///     self.esi
124///         .query("GET", RequestType::Public, &path, Some(&params), None)
125///         .await
126/// }
127/// ```
128#[macro_export]
129macro_rules! api_get {
130    (
131        $(#[$m:meta])*
132        $fn_name:ident,
133        $op_id:literal,
134        $visibility:expr,
135        $ret_type:ty,
136        $( ($param:ident: $param_t:ty) => $replace:literal ),*
137    ) => {
138        $(#[$m])*
139        pub async fn $fn_name(&self, $( $param: $param_t, )*) -> EsiResult<$ret_type> {
140            let path = self
141                .esi
142                .get_endpoint_for_op_id($op_id)?
143                $(
144                    .replace($replace, &$param.to_string())
145                )*;
146            self.esi.
147                query("GET", $visibility, &path, None, None)
148                .await
149        }
150    };
151    (
152        $(#[$m:meta])*
153        $fn_name:ident,
154        $op_id:literal,
155        $visibility:expr,
156        $ret_type:ty,
157        $( ($param:ident: $param_t:ty) => $replace:literal ),*
158        $( ; $( ($qparam:ident: $qparam_t:ty) => $qreplace:literal ),+ )?
159        $( ; $( Optional($opt_qparam:ident: $opt_qparam_t:ty) => $opt_qreplace:literal ),+ )?
160    ) => {
161        $(#[$m])*
162        pub async fn $fn_name(
163            &self,
164            $( $param: $param_t, )*
165            $($( $qparam: $qparam_t, )*)?
166            $($( $opt_qparam: Option<$opt_qparam_t>, )*)?
167        ) -> EsiResult<$ret_type> {
168            let path = self
169                .esi
170                .get_endpoint_for_op_id($op_id)?
171                $(
172                    .replace($replace, &$param.to_string())
173                )*;
174            let params = vec![
175                $($(
176                    ($qreplace, $qparam.to_string()),
177                )+)?
178            ];
179            $(
180                let mut params = params; // avoids unnecessary 'mut' warning
181                $(
182                    if let Some($opt_qparam) = $opt_qparam {
183                        params.push(($opt_qreplace, $opt_qparam.to_string()));
184                    }
185                )+
186            )?
187            let params: Vec<(&str, &str)> = params.iter().map(|(a, b)| (*a, &**b)).collect();
188            self.esi.
189                query("GET", $visibility, &path, Some(&params), None)
190                .await
191        }
192    };
193}
194
195/// Create a function for calling a single endpoint
196/// with a POST request.
197///
198/// Follows the structure of the `api_get!` macro, with the
199/// addition of taking an additional pair of `ident` and `ty`
200/// to name and type the data that will be passed to
201/// `serde_json::to_string` for serializing for setting the
202/// request's body.
203///
204/// # Example
205///
206/// ```rust,no_run
207/// # use esi_openapi::prelude::*;
208/// # use esi_openapi::api_post;
209/// pub struct SomeGroup<'a> {
210///     pub(crate) esi: &'a Esi,
211/// }
212///
213/// impl SomeGroup<'_> {
214///
215///     api_post!(
216///         /// Docs for the generated function
217///         function_name,
218///         "some_operation_id",
219///         RequestType::Public,
220///         Vec<u64>,
221///         (alliance_id: u64) => "{alliance_id}",
222///         ids: &[u64],
223///     );
224///
225/// }
226/// # fn main() {}
227/// ```
228/// ## Result:
229///
230/// ```rust,ignore
231/// /// Docs for the generated function
232/// pub async fn function_name(&self, alliance_id: u64, ids: &[u64]) -> EsiResult<Vec<u64>> {
233///     let path = self.esi.get_endpoint_for_op_id("some_operation_id")?
234///         .replace("{alliance_id}", &alliance_id.to_string());
235///     let body = serde_json::to_string(ids);
236///     self.esi
237///         .query("GET", RequestType::Public, &path, None, Some(&body))
238///         .await
239/// }
240/// ```
241#[macro_export]
242macro_rules! api_post {
243    (
244        $(#[$m:meta])*
245        $fn_name:ident,
246        $op_id:literal,
247        $visibility:expr,
248        $ret_type:ty,
249        $( ($param:ident: $param_t:ty) => $replace:literal ),*,
250        $body_param:ident: $param_type:ty,
251    ) => {
252        $(#[$m])*
253        pub async fn $fn_name(&self, $( $param: $param_t, )* $body_param: $param_type) -> EsiResult<$ret_type> {
254            let path = self
255                .esi
256                .get_endpoint_for_op_id($op_id)?
257                $(
258                    .replace($replace, &$param.to_string())
259                )*;
260            let body = serde_json::to_string($body_param)?;
261            self.esi.
262                query("POST", $visibility, &path, None, Some(&body))
263                .await
264        }
265    }
266}