Repository: netwo-io/apistos
Pull request #102 (2024-06-28 17:18:19)

Feat add webhook tags


Patch:
diff --git a/apistos-gen/src/callback_attr.rs b/apistos-gen/src/callback_attr.rs
index a56d36d..18915a7 100644
--- a/apistos-gen/src/callback_attr.rs
+++ b/apistos-gen/src/callback_attr.rs
@@ -40,6 +40,7 @@ pub(crate) struct CallbackAttr {
   pub(crate) summary: Option<String>,
   pub(crate) description: Option<String>,
   pub(crate) components: Vec<Type>,
+  pub(crate) tags: Vec<String>,
   pub(crate) responses: Vec<CallbackResponseDefinition>,
 }
 
@@ -59,6 +60,7 @@ impl TryFrom<CallbackAttrInternal> for CallbackAttr {
       summary: value.summary,
       description: value.description,
       components: value.components,
+      tags: vec![],
       responses: value.responses,
     })
   }
@@ -66,6 +68,7 @@ impl TryFrom<CallbackAttrInternal> for CallbackAttr {
 
 impl CallbackAttr {
   pub(crate) fn operation(&self) -> TokenStream {
+    let tags = &self.tags;
     let components = &self.components;
     let deprecated = self
       .deprecated
@@ -134,6 +137,8 @@ impl CallbackAttr {
 
       operation_builder.deprecated = #deprecated;
 
+      operation_builder.tags = vec![#(#tags.to_string(),)*];
+
       #summary
       #description
 
diff --git a/apistos-gen/src/lib.rs b/apistos-gen/src/lib.rs
index e7c2735..7eb87c7 100644
--- a/apistos-gen/src/lib.rs
+++ b/apistos-gen/src/lib.rs
@@ -498,16 +498,17 @@ pub fn derive_api_error(input: TokenStream) -> TokenStream {
 /// ```
 ///
 /// # `#[api_webhook(...)]` options:
+/// - `tag = "..."` an optional list of tags for the webhook
 /// - `skip` allow to skip an enum variant (for enum only)
 /// - `name = "..."` an optional name for the webhook. Default to the Struct or Variant name
 /// - `deprecated` a bool indicating the operation is deprecated. Deprecation can also be declared
 ///  with rust `#[deprecated]` decorator.
 /// - `summary = "..."` an optional summary
 /// - `description = "..."` an optional description
-/// - `component = "..."` an optional list of components attached to this callback operation (parameters, body...)
-/// - `response(...)` an optional list of responses attached to this callback operation
+/// - `component = "..."` an optional list of components attached to this webhook operation (parameters, body...)
+/// - `response(...)` an optional list of responses attached to this webhook operation
 ///   - `code = "..."` Http response code
-///   - `component = "..."` a component attached to the given callback response. Must derive [ApiComponent] and [JsonSchema](https://docs.rs/schemars/latest/schemars/trait.JsonSchema.html).
+///   - `component = "..."` a component attached to the given webhook response. Must derive [ApiComponent] and [JsonSchema](https://docs.rs/schemars/latest/schemars/trait.JsonSchema.html).
 #[proc_macro_error]
 #[proc_macro_derive(ApiWebhookComponent, attributes(openapi_webhook))]
 pub fn derive_api_webhook(input: TokenStream) -> TokenStream {
diff --git a/apistos-gen/src/webhook_attr.rs b/apistos-gen/src/webhook_attr.rs
index d61ba9d..28ce7a9 100644
--- a/apistos-gen/src/webhook_attr.rs
+++ b/apistos-gen/src/webhook_attr.rs
@@ -106,6 +106,8 @@ fn parse_openapi_derive_enum_webhook_attrs(_enum: &DataEnum, struct_attrs: Optio
 #[derive(FromMeta, Clone)]
 struct WebhookAttrInternal {
   name: Option<String>,
+  #[darling(default, multiple, rename = "tag")]
+  tags: Vec<String>,
   #[darling(flatten)]
   attr: CallbackAttrInternal,
 }
@@ -114,6 +116,8 @@ struct WebhookAttrInternal {
 struct WebhookAttrEnumInternal {
   #[darling(default)]
   skip: bool,
+  #[darling(default, multiple, rename = "tag")]
+  tags: Vec<String>,
   name: Option<String>,
   #[darling(flatten, default)]
   attr: CallbackAttrInternal,
@@ -131,9 +135,11 @@ impl WebhookAttrInternal {
       ));
     }
 
+    let mut callback_attr: CallbackAttr = self.attr.try_into()?;
+    callback_attr.tags = self.tags;
     Ok(WebhookAttr(BTreeMap::from_iter(vec![(
       self.name.unwrap_or(default_name),
-      self.attr.try_into()?,
+      callback_attr,
     )])))
   }
 }
@@ -164,9 +170,15 @@ impl WebhookAttrEnumInternal {
       ));
     }
 
+    let mut callback_attr: CallbackAttr = self.attr.try_into()?;
+    if self.tags.is_empty() {
+      callback_attr.tags = struct_attrs.map(|t| t.tags.clone()).unwrap_or_default();
+    } else {
+      callback_attr.tags = self.tags;
+    }
     Ok(WebhookAttr(BTreeMap::from_iter(vec![(
       self.name.unwrap_or(default_name),
-      self.attr.try_into()?,
+      callback_attr,
     )])))
   }
 }


Test patch:
diff --git a/apistos-gen-test/src/tests/api_webhook_oas_3_1.rs b/apistos-gen-test/src/tests/api_webhook_oas_3_1.rs
index a7d9e2b..c6f39c6 100644
--- a/apistos-gen-test/src/tests/api_webhook_oas_3_1.rs
+++ b/apistos-gen-test/src/tests/api_webhook_oas_3_1.rs
@@ -220,11 +220,17 @@ fn api_webhook_enum_default() {
   use test_models::OrganizationSlug;
 
   #[derive(ApiWebhookComponent)]
-  #[openapi_webhook(component = "Header<OrganizationSlug>", response(code = 200))]
+  #[openapi_webhook(
+    component = "Header<OrganizationSlug>",
+    response(code = 200),
+    tag = "tag1",
+    tag = "tag2"
+  )]
   enum TestEnum {
     Test,
     #[openapi_webhook(skip)]
     TestSkipped,
+    #[openapi_webhook(tag = "tag3")]
     Test2,
   }
 
@@ -241,6 +247,10 @@ fn api_webhook_enum_default() {
     json!({
       "Test": {
         "post": {
+          "tags": [
+            "tag1",
+            "tag2"
+          ],
           "parameters": [
             {
               "name": "X-Organization-Slug",
@@ -265,6 +275,9 @@ fn api_webhook_enum_default() {
       },
       "Test2": {
         "post": {
+          "tags": [
+            "tag3"
+          ],
           "parameters": [
             {
               "name": "X-Organization-Slug",