<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Swagger on 0AndWild_log</title><link>https://0andwild.com/en/series/swagger/</link><description>Recent content in Swagger on 0AndWild_log</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Tue, 17 Oct 2023 17:12:52 +0900</lastBuildDate><atom:link href="https://0andwild.com/en/series/swagger/index.xml" rel="self" type="application/rss+xml"/><item><title>Springdoc and OpenAPI (Annotation Usage Guide)</title><link>https://0andwild.com/en/posts/231017_swagger/</link><pubDate>Tue, 17 Oct 2023 17:12:52 +0900</pubDate><guid>https://0andwild.com/en/posts/231017_swagger/</guid><description>&lt;img src="https://0andwild.com/" alt="Featured image of post Springdoc and OpenAPI (Annotation Usage Guide)" /&gt;&lt;h2 id="querystring-processing-methods-comparison"&gt;&lt;a href="#querystring-processing-methods-comparison" class="header-anchor"&gt;&lt;/a&gt;QueryString Processing Methods Comparison
&lt;/h2&gt;&lt;p&gt;Let&amp;rsquo;s compare two methods for handling QueryString in Spring.&lt;/p&gt;
&lt;h3 id="method-1-receiving-as-object-parameterobject"&gt;&lt;a href="#method-1-receiving-as-object-parameterobject" class="header-anchor"&gt;&lt;/a&gt;Method 1: Receiving as Object (ParameterObject)
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;swagger&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/hello/parameters1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResponseTest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;parameterObjectTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParameterObjectReq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResponseTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResponseTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;occupation&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResponseEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="method-2-receiving-as-individual-parameters-requestparam"&gt;&lt;a href="#method-2-receiving-as-individual-parameters-requestparam" class="header-anchor"&gt;&lt;/a&gt;Method 2: Receiving as Individual Parameters (@RequestParam)
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;swagger&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/hello/parameters2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResponseTest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;parameterObjectTest2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;pw&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;oq&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OccupationStatus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResponseTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResponseTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResponseEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="model-definition"&gt;&lt;a href="#model-definition" class="header-anchor"&gt;&lt;/a&gt;Model Definition
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;ParameterObjectReq (Request DTO)&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;ParameterObjectReq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OccupationStatus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;occupation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;OccupationStatus (Enum)&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OccupationStatus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STUDENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EMPLOYEE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UNEMPLOYED&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="differences-between-the-two-approaches"&gt;&lt;a href="#differences-between-the-two-approaches" class="header-anchor"&gt;&lt;/a&gt;Differences Between the Two Approaches
&lt;/h3&gt;&lt;p&gt;While &lt;code&gt;@RequestParam&lt;/code&gt; is commonly used for receiving QueryString requests, when there are many parameters, you can receive the QueryString as an Object like in the first method.&lt;/p&gt;
&lt;h4 id="requestparam-vs-parameterobject"&gt;&lt;a href="#requestparam-vs-parameterobject" class="header-anchor"&gt;&lt;/a&gt;@RequestParam vs ParameterObject
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;@RequestParam&lt;/strong&gt;: By default set to &lt;code&gt;required = true&lt;/code&gt;, making request values mandatory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ParameterObject&lt;/strong&gt;: Spring automatically binds QueryString to the object&amp;rsquo;s field values without any special annotation. However, since &lt;code&gt;required&lt;/code&gt; is not set by default, &lt;code&gt;null&lt;/code&gt; values can be passed.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="parameterobject-vs-requestparam-conversion-in-springdoc"&gt;&lt;a href="#parameterobject-vs-requestparam-conversion-in-springdoc" class="header-anchor"&gt;&lt;/a&gt;ParameterObject vs @RequestParam Conversion in Springdoc
&lt;/h2&gt;&lt;h3 id="using-parameterobject"&gt;&lt;a href="#using-parameterobject" class="header-anchor"&gt;&lt;/a&gt;Using ParameterObject
&lt;/h3&gt;&lt;p&gt;&lt;img alt="ParameterObject Conversion Result" class="gallery-image" data-flex-basis="273px" data-flex-grow="114" height="817" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://0andwild.com/posts/231017_swagger/image1.png" srcset="https://0andwild.com/posts/231017_swagger/image1_hu_f885b6e7782bc66a.png 800w, https://0andwild.com/posts/231017_swagger/image1.png 932w" width="932"&gt;&lt;/p&gt;
&lt;h3 id="using-requestparam"&gt;&lt;a href="#using-requestparam" class="header-anchor"&gt;&lt;/a&gt;Using @RequestParam
&lt;/h3&gt;&lt;p&gt;&lt;img alt="RequestParam Conversion Result" class="gallery-image" data-flex-basis="286px" data-flex-grow="119" height="776" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://0andwild.com/posts/231017_swagger/image2.png" srcset="https://0andwild.com/posts/231017_swagger/image2_hu_f9e153109139ffab.png 800w, https://0andwild.com/posts/231017_swagger/image2.png 927w" width="927"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="using-parameterobject-annotation"&gt;&lt;a href="#using-parameterobject-annotation" class="header-anchor"&gt;&lt;/a&gt;Using @ParameterObject Annotation
&lt;/h2&gt;&lt;p&gt;To make Springdoc convert ParameterObject like when using &lt;code&gt;@RequestParam&lt;/code&gt; and display the Required status, configure as follows.&lt;/p&gt;
&lt;h3 id="code-example"&gt;&lt;a href="#code-example" class="header-anchor"&gt;&lt;/a&gt;Code Example
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@ParameterObject&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;ParameterObjectReq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OccupationStatus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;occupation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;@ParameterObject&lt;/code&gt; is a Springdoc annotation. When receiving multiple QueryStrings as an Object, specifying it on the class will make it recognize and convert like &lt;code&gt;@RequestParam&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Conversion Result in Swagger UI" class="gallery-image" data-flex-basis="306px" data-flex-grow="127" height="356" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://0andwild.com/posts/231017_swagger/image3.png" width="454"&gt;&lt;/p&gt;
&lt;h3 id="jsr-303-support"&gt;&lt;a href="#jsr-303-support" class="header-anchor"&gt;&lt;/a&gt;JSR-303 Support
&lt;/h3&gt;&lt;p&gt;Springdoc supports JSR-303 and allows the following validation annotations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@NotNull&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Min&lt;/code&gt;, &lt;code&gt;@Max&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Size&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Other validation annotations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;According to Springdoc official documentation&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;This library supports&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenAPI 3&lt;/li&gt;
&lt;li&gt;Spring-boot (v1, v2 and v3)&lt;/li&gt;
&lt;li&gt;JSR-303, specifically for @NotNull, @Min, @Max, and @Size&lt;/li&gt;
&lt;li&gt;Swagger-ui&lt;/li&gt;
&lt;li&gt;OAuth 2&lt;/li&gt;
&lt;li&gt;GraalVM native images&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;h3 id="conversion-result"&gt;&lt;a href="#conversion-result" class="header-anchor"&gt;&lt;/a&gt;Conversion Result
&lt;/h3&gt;&lt;p&gt;The spec file is written so that ParameterObject is also recognized as &lt;code&gt;@RequestParam&lt;/code&gt;, and &lt;code&gt;occupation&lt;/code&gt; without &lt;code&gt;@NotNull&lt;/code&gt; is displayed as optional in the Required field.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Spec File Conversion Result" class="gallery-image" data-flex-basis="276px" data-flex-grow="115" height="796" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://0andwild.com/posts/231017_swagger/image4.png" srcset="https://0andwild.com/posts/231017_swagger/image4_hu_cdd618ca02446726.png 800w, https://0andwild.com/posts/231017_swagger/image4.png 918w" width="918"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Swagger UI Display Result" class="gallery-image" data-flex-basis="563px" data-flex-grow="234" height="701" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://0andwild.com/posts/231017_swagger/image5.png" srcset="https://0andwild.com/posts/231017_swagger/image5_hu_7431e11af6515756.png 800w, https://0andwild.com/posts/231017_swagger/image5_hu_1a8ba9c724b92688.png 1600w, https://0andwild.com/posts/231017_swagger/image5.png 1647w" width="1647"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Left Image&lt;/strong&gt;: When &lt;code&gt;@ParameterObject&lt;/code&gt; is specified, Springdoc recognizes it and converts to proper spec&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="swagger2--swagger3-annotations"&gt;&lt;a href="#swagger2--swagger3-annotations" class="header-anchor"&gt;&lt;/a&gt;Swagger2 → Swagger3 Annotations
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Swagger2&lt;/th&gt;
					&lt;th&gt;Swagger3&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;@Api&lt;/td&gt;
					&lt;td&gt;@Tag&lt;/td&gt;
					&lt;td&gt;Displays swagger resource at class level (for grouping)&lt;br&gt;&lt;br&gt;&lt;code&gt;name&lt;/code&gt; : Tag name&lt;br&gt;&lt;code&gt;description&lt;/code&gt; : Tag description&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;@ApiIgnore&lt;/td&gt;
					&lt;td&gt;@Parameter(hidden = true)&lt;br&gt;@Operation(hidden = true)&lt;br&gt;@Hidden&lt;/td&gt;
					&lt;td&gt;This annotation allows hiding parameters in swagger-ui.&lt;br&gt;&lt;br&gt;For requestBody or ResponseBody, use&lt;br&gt;@JsonProperty(access = JsonProperty.Access.READ_ONLY)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;@ApiImplicitParam&lt;/td&gt;
					&lt;td&gt;@Parameter&lt;/td&gt;
					&lt;td&gt;Configuration and resource display for single RequestParam&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;@ApiImplicitParams&lt;/td&gt;
					&lt;td&gt;@Parameters&lt;/td&gt;
					&lt;td&gt;Configuration for multiple RequestParams&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;@ApiModel&lt;/td&gt;
					&lt;td&gt;@Schema&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;description&lt;/code&gt; : Human-readable name&lt;br&gt;&lt;code&gt;defaultValue&lt;/code&gt; : Default value&lt;br&gt;&lt;code&gt;allowableValues&lt;/code&gt; : Allowable values (set when enumerable)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;@ApiModelProperty(hidden = true)&lt;/td&gt;
					&lt;td&gt;@Schema(accessMode = READ_ONLY)&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;@ApiOperation(value = &amp;ldquo;foo&amp;rdquo;, notes = &amp;ldquo;bar&amp;rdquo;)&lt;/td&gt;
					&lt;td&gt;@Operation(summary = &amp;ldquo;foo&amp;rdquo;, description = &amp;ldquo;bar&amp;rdquo;)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;summary&lt;/code&gt; : Brief description of API&lt;br&gt;&lt;code&gt;description&lt;/code&gt; : Detailed description of API&lt;br&gt;&lt;code&gt;responses&lt;/code&gt; : List of API responses&lt;br&gt;&lt;code&gt;parameters&lt;/code&gt; : List of API parameters&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;@ApiParam&lt;/td&gt;
					&lt;td&gt;@Parameter&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;name&lt;/code&gt; : Parameter name&lt;br&gt;&lt;code&gt;description&lt;/code&gt; : Parameter description&lt;br&gt;&lt;code&gt;in&lt;/code&gt; : Parameter location (query, header, path, cookie)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;@ApiResponse(code = 404, message = &amp;ldquo;foo&amp;rdquo;)&lt;/td&gt;
					&lt;td&gt;@ApiResponse(responseCode = &amp;ldquo;404&amp;rdquo;, description = &amp;ldquo;foo&amp;rdquo;)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;responseCode&lt;/code&gt; : HTTP status code&lt;br&gt;&lt;code&gt;description&lt;/code&gt; : Response description&lt;br&gt;&lt;code&gt;content&lt;/code&gt; : Response payload structure&lt;br&gt;&lt;code&gt;schema&lt;/code&gt; : Schema used in payload&lt;br&gt;&lt;br&gt;&lt;code&gt;hidden&lt;/code&gt; : Whether to hide schema&lt;br&gt;&lt;code&gt;implementation&lt;/code&gt; : Schema target class&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;When using an object to capture multiple request query params, use the &lt;code&gt;@ParameterObject&lt;/code&gt; annotation on that method argument&lt;/li&gt;
&lt;li&gt;This step is optional: Replace with &lt;code&gt;GroupedOpenApi&lt;/code&gt; bean only if you have &lt;strong&gt;multiple&lt;/strong&gt; &lt;code&gt;Docket&lt;/code&gt; beans&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="using-tag-annotation"&gt;&lt;a href="#using-tag-annotation" class="header-anchor"&gt;&lt;/a&gt;Using @Tag Annotation
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;@Tag&lt;/code&gt; annotation enables the following grouping:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Grouping by Controller&lt;/li&gt;
&lt;li&gt;Grouping by method within Controller&lt;/li&gt;
&lt;li&gt;Grouping in spec file conversion according to the name specified in &lt;code&gt;@Tag&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;File creation with that name when generating client code using OpenAPI Generator&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cautions-when-using-multiple-tag"&gt;&lt;a href="#cautions-when-using-multiple-tag" class="header-anchor"&gt;&lt;/a&gt;Cautions When Using Multiple @Tag
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: What happens if you group with &lt;code&gt;@Tag&lt;/code&gt; at the top level and set a different tag name in the &lt;code&gt;@Operation&lt;/code&gt; of a lower-level method?&lt;/p&gt;
&lt;h4 id="test-result"&gt;&lt;a href="#test-result" class="header-anchor"&gt;&lt;/a&gt;Test Result
&lt;/h4&gt;&lt;p&gt;&lt;img alt="Duplicate Group Creation Result" class="gallery-image" data-flex-basis="442px" data-flex-grow="184" height="573" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://0andwild.com/posts/231017_swagger/image6.png" srcset="https://0andwild.com/posts/231017_swagger/image6_hu_3cbed8043027dda1.png 800w, https://0andwild.com/posts/231017_swagger/image6.png 1056w" width="1056"&gt;&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;@Tag(name = &amp;quot;swagger&amp;quot;)&lt;/code&gt; is set at the top level and &lt;code&gt;tags = {&amp;quot;swagger123&amp;quot;}&lt;/code&gt; is added in the &lt;code&gt;@Operation&lt;/code&gt; of the &lt;code&gt;postHello&lt;/code&gt; method, the same endpoint is created as duplicate groups.&lt;/p&gt;
&lt;h4 id="problem"&gt;&lt;a href="#problem" class="header-anchor"&gt;&lt;/a&gt;Problem
&lt;/h4&gt;&lt;p&gt;Using OpenAPI Generator in this state causes the problem of duplicate client code being generated as shown below.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Duplicate Generated API File 1" class="gallery-image" data-flex-basis="728px" data-flex-grow="303" height="510" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://0andwild.com/posts/231017_swagger/image7.png" srcset="https://0andwild.com/posts/231017_swagger/image7_hu_49839dee49b39d87.png 800w, https://0andwild.com/posts/231017_swagger/image7.png 1548w" width="1548"&gt;
&lt;img alt="Duplicate Generated API File 2" class="gallery-image" data-flex-basis="269px" data-flex-grow="112" height="673" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://0andwild.com/posts/231017_swagger/image8.png" width="757"&gt;
&lt;img alt="Duplicate Generated API File 3" class="gallery-image" data-flex-basis="428px" data-flex-grow="178" height="174" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://0andwild.com/posts/231017_swagger/image9.png" width="311"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: Unless there&amp;rsquo;s a special case, it&amp;rsquo;s recommended to use &lt;code&gt;@Tag&lt;/code&gt; grouping only at the Controller&amp;rsquo;s top level.&lt;/p&gt;
&lt;h3 id="file-naming-for-openapi-generator-client-code-generation"&gt;&lt;a href="#file-naming-for-openapi-generator-client-code-generation" class="header-anchor"&gt;&lt;/a&gt;File Naming for OpenAPI Generator Client Code Generation
&lt;/h3&gt;&lt;p&gt;When generating client code, the name specified in &lt;code&gt;@Tag&lt;/code&gt; + &lt;code&gt;-api&lt;/code&gt; is added as a postfix. To customize this, you need to modify the Mustache file.&lt;/p&gt;
&lt;h3 id="references"&gt;&lt;a href="#references" class="header-anchor"&gt;&lt;/a&gt;References
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://openapi-generator.tech/docs/templating" target="_blank" rel="noopener"
 &gt;Using Templates | OpenAPI Generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/janl/mustache.js" target="_blank" rel="noopener"
 &gt;Mustache.js GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hmos.dev/how-to-use-oas-generator" target="_blank" rel="noopener"
 &gt;OpenAPI Generator Usage Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://velog.io/@kdeun1/OpenAPI-Generator%eb%a5%bc-%ec%82%ac%ec%9a%a9%ed%95%98%ec%97%ac-API%ec%99%80-%eb%8f%99%ec%9d%bc%ed%95%9c-Model%ea%b3%bc-%ec%a0%95%ed%98%95%ed%99%94%eb%90%9c-API%ec%bd%94%eb%93%9c-%ec%9e%90%eb%8f%99%ec%83%9d%ec%84%b1%ed%95%98%ea%b8%b0" target="_blank" rel="noopener"
 &gt;Auto-generating Safe Models and Standardized Implementation Code with OpenAPI Generator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="authentication-related-openapi-specs"&gt;&lt;a href="#authentication-related-openapi-specs" class="header-anchor"&gt;&lt;/a&gt;Authentication-Related OpenAPI Specs
&lt;/h2&gt;&lt;p&gt;OpenAPI supports various authentication methods. Key configuration items are as follows.&lt;/p&gt;
&lt;h3 id="type-authentication-format"&gt;&lt;a href="#type-authentication-format" class="header-anchor"&gt;&lt;/a&gt;type (Authentication Format)
&lt;/h3&gt;&lt;p&gt;Currently supports API Key, HTTP, OAuth2, and OpenID Connect methods.
&lt;strong&gt;Note&lt;/strong&gt;: OpenAPI v2 spec does not support OpenID Connect method.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Supported Types&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http&lt;/code&gt;: Basic, Bearer and other HTTP authentication schemes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apiKey&lt;/code&gt;: API key and cookie authentication&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oauth2&lt;/code&gt;: OAuth2 authentication&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openIdConnect&lt;/code&gt;: OpenID Connect discovery&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="key-configuration-items"&gt;&lt;a href="#key-configuration-items" class="header-anchor"&gt;&lt;/a&gt;Key Configuration Items
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;name&lt;/code&gt;&lt;/strong&gt;: Authentication key name (required when using API Key method)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;in&lt;/code&gt;&lt;/strong&gt;: Specifies authentication key location (choose from &lt;code&gt;query&lt;/code&gt;, &lt;code&gt;header&lt;/code&gt;, &lt;code&gt;cookie&lt;/code&gt;, required when using API Key method)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;scheme&lt;/code&gt;&lt;/strong&gt;: Specifies authentication method (&lt;code&gt;Basic&lt;/code&gt; or &lt;code&gt;Bearer&lt;/code&gt;, required when using HTTP authentication)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;bearerFormat&lt;/code&gt;&lt;/strong&gt;: Bearer token format (commonly &lt;code&gt;JWT&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;flows&lt;/code&gt;&lt;/strong&gt;: OAuth2 flow type (choose from &lt;code&gt;implicit&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt;, &lt;code&gt;clientCredentials&lt;/code&gt;, &lt;code&gt;authorizationCode&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;openIdConnectUrl&lt;/code&gt;&lt;/strong&gt;: OpenID Connect URL (recommended to use OAuth2 or Bearer token method as alternative in OpenAPI v2 spec)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="deprecated-strategy"&gt;&lt;a href="#deprecated-strategy" class="header-anchor"&gt;&lt;/a&gt;@Deprecated Strategy
&lt;/h2&gt;&lt;p&gt;When there are changes to DTO specs due to API version updates, use the following phased strategy.&lt;/p&gt;
&lt;h3 id="phase-1-mark-with-deprecated"&gt;&lt;a href="#phase-1-mark-with-deprecated" class="header-anchor"&gt;&lt;/a&gt;Phase 1: Mark with @Deprecated
&lt;/h3&gt;&lt;p&gt;First, add the &lt;code&gt;@Deprecated&lt;/code&gt; annotation to the field that will change.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserDto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Deprecated&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oldField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The OpenAPI spec will also show &lt;code&gt;deprecated&lt;/code&gt; for that schema field, and when generating code on the frontend, the field will be marked as deprecated. This notifies the frontend team in advance that the field will be removed soon.&lt;/p&gt;
&lt;h3 id="phase-2-apply-schemahidden--true"&gt;&lt;a href="#phase-2-apply-schemahidden--true" class="header-anchor"&gt;&lt;/a&gt;Phase 2: Apply @Schema(hidden = true)
&lt;/h3&gt;&lt;p&gt;Once the frontend has completed migration to the new spec, add &lt;code&gt;@Schema(hidden = true)&lt;/code&gt; to the &lt;code&gt;@Deprecated&lt;/code&gt; field on the server so that the field is no longer generated in the OpenAPI spec.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserDto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Deprecated&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hidden&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oldField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Excluded from spec&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="phase-3-remove-field"&gt;&lt;a href="#phase-3-remove-field" class="header-anchor"&gt;&lt;/a&gt;Phase 3: Remove Field
&lt;/h3&gt;&lt;p&gt;After sufficient time has passed, completely remove the field.&lt;/p&gt;
&lt;p&gt;This phased approach enables safe API version management between frontend and backend.&lt;/p&gt;</description></item><item><title>Mastering OpenAPI Generator</title><link>https://0andwild.com/en/posts/231016_swagger/</link><pubDate>Mon, 16 Oct 2023 16:56:35 +0900</pubDate><guid>https://0andwild.com/en/posts/231016_swagger/</guid><description>&lt;img src="https://0andwild.com/" alt="Featured image of post Mastering OpenAPI Generator" /&gt;&lt;h2 id="what-is-swagger"&gt;&lt;a href="#what-is-swagger" class="header-anchor"&gt;&lt;/a&gt;What is Swagger?
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Swagger&lt;/strong&gt; is a framework for OAS (OpenAPI Specification) that allows you to specify and manage the specifications of APIs. Through Swagger, you can design, build, and document REST API services.&lt;/p&gt;
&lt;h3 id="swagger-tools"&gt;&lt;a href="#swagger-tools" class="header-anchor"&gt;&lt;/a&gt;Swagger Tools
&lt;/h3&gt;&lt;p&gt;Swagger provides the following key tools&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Swagger UI&lt;/strong&gt;: A tool that visualizes Swagger API specifications in HTML format for easy viewing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Swagger Codegen&lt;/strong&gt;: A CLI tool that automatically generates client and server code based on Swagger specifications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Swagger Editor&lt;/strong&gt;: An editor for creating API design documents and specifications according to Swagger standards&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="springfox-vs-springdoc"&gt;&lt;a href="#springfox-vs-springdoc" class="header-anchor"&gt;&lt;/a&gt;Springfox vs Springdoc
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Springfox Swagger&lt;/strong&gt; is a library that helps you easily write API documentation using Swagger in projects using Spring or Spring Boot.&lt;/p&gt;
&lt;p&gt;When Springfox stopped updating, &lt;strong&gt;Springdoc&lt;/strong&gt; emerged and rapidly gained popularity with active updates. Springdoc is also a library that supports Swagger documentation creation and is now the more recommended choice over Springfox.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="swagger-codegen-vs-openapi-generator"&gt;&lt;a href="#swagger-codegen-vs-openapi-generator" class="header-anchor"&gt;&lt;/a&gt;Swagger Codegen vs OpenAPI Generator
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Swagger&lt;/strong&gt; is a trademark of SmartBear, and &lt;strong&gt;Swagger Codegen&lt;/strong&gt; is a project included within it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OpenAPI Generator&lt;/strong&gt; is a community-driven open-source project that started as a fork of the Swagger Codegen project. Currently, more than 40 top project contributors and founding members of Swagger Codegen are participating together.&lt;/p&gt;
&lt;h3 id="openapi-generator-license"&gt;&lt;a href="#openapi-generator-license" class="header-anchor"&gt;&lt;/a&gt;OpenAPI Generator License
&lt;/h3&gt;&lt;p&gt;OpenAPI Generator follows &lt;strong&gt;Apache License 2.0&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id="what-is-apache-license-20"&gt;&lt;a href="#what-is-apache-license-20" class="header-anchor"&gt;&lt;/a&gt;What is Apache License 2.0?
&lt;/h4&gt;&lt;p&gt;Apache License 2.0 grants the following rights&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anyone can create programs derived from the software&lt;/li&gt;
&lt;li&gt;Copyright can be transferred and transmitted&lt;/li&gt;
&lt;li&gt;Parts or the whole can be used for personal or commercial purposes&lt;/li&gt;
&lt;li&gt;When redistributing, you don&amp;rsquo;t necessarily have to include the original or modified source code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;However, you must include the Apache License version and notice&lt;/strong&gt; (clearly indicating that the software was developed under Apache License)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="background-of-openapi-generators-birth"&gt;&lt;a href="#background-of-openapi-generators-birth" class="header-anchor"&gt;&lt;/a&gt;Background of OpenAPI Generator&amp;rsquo;s Birth
&lt;/h3&gt;&lt;p&gt;The official Q&amp;amp;A of OpenAPI Generator reveals the background of the project&amp;rsquo;s creation&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Difference in Version Philosophy&lt;/strong&gt;
The founding members of Swagger Codegen felt that Swagger Codegen 3.0.0 was too different from the 2.x philosophy. They were concerned that the overhead of maintaining two separate branches (2.x, 3.x) could cause problems similar to those experienced by the Python community.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Faster Release Cycle&lt;/strong&gt;
The founding members wanted a faster release cycle so users wouldn&amp;rsquo;t have to wait months to use the stable release version they wanted.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Weekly patch releases&lt;/li&gt;
&lt;li&gt;Monthly minor releases&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Community-Driven Development&lt;/strong&gt;
Proceeding as a community-driven open-source project ensures innovation, reliability, and a roadmap owned by the community.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For these reasons, the OpenAPI Generator project was born. OpenAPI Generator feels somewhat like the relationship between MySQL and MariaDB.&lt;/p&gt;
&lt;h3 id="migrating-from-swagger-codegen"&gt;&lt;a href="#migrating-from-swagger-codegen" class="header-anchor"&gt;&lt;/a&gt;Migrating from Swagger Codegen
&lt;/h3&gt;&lt;p&gt;According to the official documentation, if you&amp;rsquo;re currently using Swagger Codegen 2.x version, you can conveniently migrate to OpenAPI Generator. This is because OpenAPI Generator is based on Swagger Codegen 2.4.0-SNAPSHOT version.&lt;/p&gt;
&lt;p&gt;For detailed migration instructions, refer to the official guide&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://openapi-generator.tech/docs/swagger-codegen-migration" target="_blank" rel="noopener"
 &gt;Migrating from Swagger Codegen | OpenAPI Generator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="references"&gt;&lt;a href="#references" class="header-anchor"&gt;&lt;/a&gt;References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://openapi-generator.tech/" target="_blank" rel="noopener"
 &gt;OpenAPI Generator Official Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://openapi-generator.tech/docs/swagger-codegen-migration" target="_blank" rel="noopener"
 &gt;Migrating from Swagger Codegen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>