Repository: juhaku/utoipa (Rust)

Issue:
"identifier" field missing from license
Great crate!

One thing I noticed while I dabbled in updating to the 5.0.0, and my pre-commit hooks found (I use lin-openapi). The license object does not support specifying an identifier, see: https://spec.openapis.org/oas/latest.html#fixed-fields-2  . This errors on that particular check, but I did notice the License object defined here https://github.com/juhaku/utoipa/blob/master/utoipa/src/openapi/info.rs#L207-L218 did not contain it. I did a quick git search for any issues that were tracking it and couldn't find it, so decided to open this


Discussion: Oh, thanks for reporting, this must have been missed when updating to 3.1 from 3.0 as 3.0 does not have this field. Need to add this.
PR #1140 is on the way which adds identifier field. It can also be derived. But by default it is not going to be filled.



Fix (patch):
diff --git a/utoipa-gen/CHANGELOG.md b/utoipa-gen/CHANGELOG.md
index 6c95848e..6b516be3 100644
--- a/utoipa-gen/CHANGELOG.md
+++ b/utoipa-gen/CHANGELOG.md
@@ -4,6 +4,7 @@
 
 ### Added
 
+* Add `identifier` for `Info` (https://github.com/juhaku/utoipa/pull/1140)
 * Add `no_recursion` feature for `ToSchema` (https://github.com/juhaku/utoipa/pull/1137)
 
 ### Fixed
diff --git a/utoipa-gen/src/openapi/info.rs b/utoipa-gen/src/openapi/info.rs
index 6973fb4e..76729550 100644
--- a/utoipa-gen/src/openapi/info.rs
+++ b/utoipa-gen/src/openapi/info.rs
@@ -179,6 +179,7 @@ impl ToTokens for Info<'_> {
 pub(super) struct License<'l> {
     name: Cow<'l, str>,
     url: Option<Cow<'l, str>>,
+    identifier: Cow<'l, str>,
 }
 
 impl Parse for License<'_> {
@@ -200,6 +201,11 @@ impl Parse for License<'_> {
                         parse_utils::parse_next(input, || input.parse::<LitStr>())?.value(),
                     ))
                 }
+                "identifier" => {
+                    license.identifier = Cow::Owned(
+                        parse_utils::parse_next(input, || input.parse::<LitStr>())?.value(),
+                    )
+                }
                 _ => {
                     return Err(Error::new(
                         ident.span(),
@@ -222,11 +228,18 @@ impl ToTokens for License<'_> {
     fn to_tokens(&self, tokens: &mut TokenStream2) {
         let name = &self.name;
         let url = self.url.as_ref().map(|url| quote! { .url(Some(#url))});
+        let identifier = if !self.identifier.is_empty() {
+            let identifier = self.identifier.as_ref();
+            quote! { .identifier(Some(#identifier))}
+        } else {
+            TokenStream2::new()
+        };
 
         tokens.extend(quote! {
             utoipa::openapi::info::LicenseBuilder::new()
                 .name(#name)
                 #url
+                #identifier
                 .build()
         })
     }
diff --git a/utoipa/CHANGELOG.md b/utoipa/CHANGELOG.md
index 77b43bdb..e236da93 100644
--- a/utoipa/CHANGELOG.md
+++ b/utoipa/CHANGELOG.md
@@ -7,6 +7,7 @@ to look into changes introduced to **`utoipa-gen`**.
 
 ### Added
 
+* Add `identifier` for `Info` (https://github.com/juhaku/utoipa/pull/1140)
 * Implement schema traits for indexset (https://github.com/juhaku/utoipa/pull/1129)
 * Add `ToSchema` implementation for serde_json::Value (https://github.com/juhaku/utoipa/pull/1132)
 
diff --git a/utoipa/src/openapi/info.rs b/utoipa/src/openapi/info.rs
index d6e64207..0df2bf35 100644
--- a/utoipa/src/openapi/info.rs
+++ b/utoipa/src/openapi/info.rs
@@ -212,6 +212,13 @@ builder! {
         #[serde(skip_serializing_if = "Option::is_none")]
         pub url: Option<String>,
 
+        /// An [SPDX-Licenses][spdx_licence] expression for the API. The _`identifier`_ field
+        /// is mutually exclusive of the _`url`_ field. E.g. Apache-2.0
+        ///
+        /// [spdx_licence]: <https://spdx.org/licenses/>
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub identifier: Option<String>,
+
         /// Optional extensions "x-something".
         #[serde(skip_serializing_if = "Option::is_none", flatten)]
         pub extensions: Option<Extensions>,
@@ -245,6 +252,14 @@ impl LicenseBuilder {
     pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
         set_value!(self extensions extensions)
     }
+
+    /// Set identifier of the licence as [SPDX-Licenses][spdx_licence] expression for the API.
+    /// The _`identifier`_ field is mutually exclusive of the _`url`_ field. E.g. Apache-2.0
+    ///
+    /// [spdx_licence]: <https://spdx.org/licenses/>
+    pub fn identifier<S: Into<String>>(mut self, identifier: Option<S>) -> Self {
+        set_value!(self identifier identifier.map(|identifier| identifier.into()))
+    }
 }
 
 #[cfg(test)]