avatarEsteban Thilliez

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

13475

Abstract

s="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">example:</span> <span class="hljs-number">123456</span> <span class="hljs-attr">name:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">example:</span> <span class="hljs-string">A</span> <span class="hljs-string">product</span> <span class="hljs-attr">description:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">price:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">number</span> <span class="hljs-attr">required:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">productId</span> <span class="hljs-bullet">-</span> <span class="hljs-string">name</span> <span class="hljs-bullet">-</span> <span class="hljs-string">description</span> <span class="hljs-bullet">-</span> <span class="hljs-string">price</span></pre></div><h2 id="a237">Specifying our Endpoints</h2><p id="28c0">To specify our endpoints, we need to add a <code>paths</code> object to our file. This object contains as many paths as you want, and a path object can contain each HTTP method.</p><p id="85df">OpenAPI 3.0 supports <code>get</code>, <code>post</code>, <code>put</code>, <code>patch</code>, <code>delete</code>, <code>head</code>, <code>options</code>, and <code>trace</code>.</p><p id="1515">OpenAPI defines operations as a combination of a path and a method. Then, each operation may have some attributes including <code>description</code> , <code>summary</code> , <code>responses</code> , <code>parameters</code> , etc…</p><p id="7f48">Let’s start with our first operation: GET all products.</p><div id="81df"><pre><span class="hljs-attr">paths:</span> <span class="hljs-string">/products:</span> <span class="hljs-attr">get:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Return</span> <span class="hljs-string">all</span> <span class="hljs-string">products</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-attr">description:</span> <span class="hljs-string">OK</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">example:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">productId:</span> <span class="hljs-string">"123456"</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"Example Product"</span> <span class="hljs-attr">description:</span> <span class="hljs-string">"This is an example product"</span> <span class="hljs-attr">price:</span> <span class="hljs-number">19.99</span></pre></div><p id="3e04">It takes no parameters and returns a list of products.</p><p id="0c77">The <code>responses</code> object can contain as many responses as you want. Each response has a content and a description. You can specify an example in the content if you want. But you can also specify a schema, such as the schemas we’ve defined just before. And even better, you can add a reference to an existing schema:</p><div id="158d"><pre><span class="hljs-attr">paths:</span> <span class="hljs-string">/products:</span> <span class="hljs-attr">get:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Return</span> <span class="hljs-string">all</span> <span class="hljs-string">products</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-attr">description:</span> <span class="hljs-string">OK</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">schema:</span> <span class="hljs-string">ref:</span> <span class="hljs-string">'#/components/schemas/Product'</span></pre></div><p id="cf2e">Now, imagine we want to add an operation that takes parameters. Let’s see how to do this:</p><div id="38fa"><pre> <span class="hljs-string">/products/{id}:</span> <span class="hljs-attr">get:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Return</span> <span class="hljs-string">a</span> <span class="hljs-string">product</span> <span class="hljs-string">with</span> <span class="hljs-string">productId</span> <span class="hljs-attr">parameters:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">in:</span> <span class="hljs-string">path</span> <span class="hljs-attr">name:</span> <span class="hljs-string">id</span> <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">schema:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-attr">description:</span> <span class="hljs-string">OK</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">schema:</span> <span class="hljs-string">ref:</span> <span class="hljs-string">'#/components/schemas/Product'</span></pre></div><p id="404b">Here, we’ve added the <code>/products/{id}</code> path. <code>id</code> is a parameter, so we should use brackets. Then, we add a <code>parameters</code> object containing the list of our parameters. Here, we just have one. We specify the location of the parameter (query, path…), its name, if it is required, and its schema. We can also add a description and an example if we want.</p><p id="5672">Now, let’s move on to an operation that requires a request body:</p><div id="a7c9"><pre><span class="hljs-attr">paths:</span> <span class="hljs-string">/products:</span> <span class="hljs-attr">post:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Add</span> <span class="hljs-string">a</span> <span class="hljs-string">product</span> <span class="hljs-attr">requestBody:</span> <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">schema:</span> <span class="hljs-string">ref:</span> <span class="hljs-string">'#/components/schemas/Product'</span></pre></div><p id="d276">We just add a <code>requestBody</code> object, specify whether it’s required, and its content.</p><p id="a2a0">Now, you know everything you need to know to add the remaining operations.</p><h2 id="fe04">Security</h2><p id="0ce7">We can add security schemes in the <code>securitySchemes</code> object. For example, if we want to secure our API with an API key:</p><div id="037b"><pre> <span class="hljs-attr">securitySchemes:</span> <span class="hljs-attr">ApiKeyAuth:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">apiKey</span> <span class="hljs-attr">in:</span> <span class="hljs-string">header</span> <span class="hljs-attr">name:</span> <span class="hljs-string">X-API-Key</span></pre></div><p id="743b">There are many authentication mechanisms available, check the <a href="https://swagger.io/docs/specification/about/">doc</a> for more details.</p><h2 id="197b">Tags</h2><p id="421c">You can add tags if you want to organize your operations. First, add a <code>tags</code> object:</p><div id="66f8"><pre><span class="hljs-attr">tags:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Products</span> <span class="hljs-attr">description:</span> <span class="hljs-string">Everything</span> <span class="hljs-string">about</span> <span class="hljs-string">products</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Orders</span> <span class="hljs-attr">description:</span> <span class="hljs-string">Everything</span> <span class="hljs-string">about</span> <span class="hljs-string">orders</span></pre></div><p id="64c0">Then, add tags to operations:</p><div id="0981"><pre><span class="hljs-attr">paths:</span> <span class="hljs-string">/products:</span> <span class="hljs-attr">get:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Return</span> <span class="hljs-string">all</span> <span class="hljs-string">products</span> <span class="hljs-attr">tags:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">Products</span></pre></div><h2 id="6426">Putting It All Together</h2><p id="61b2">Here is an example of a whole <code>openapi.yaml</code> file:</p><div id="9232"><pre><span class="hljs-attr">openapi:</span> <span class="hljs-number">3.0</span><span class="hljs-number">.0</span> <span class="hljs-attr">info:</span> <span class="hljs-attr">title:</span> <span class="hljs-string">Example</span> <span class="hljs-string">API</span> <span class="hljs-attr">version:</span> <span class="hljs-number">1.0</span><span class="hljs-number">.0</span> <span class="hljs-attr">servers:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">url:</span> <span class="hljs-string">https://localhost:8080/api</span> <span class="hljs-attr">tags:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Products</span> <span class="hljs-attr">description:</span> <span class="hljs-string">Everything</span> <span class="hljs-string">about</span> <span class="hljs-string">products</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Orders</span> <span class="hljs-attr">description:</span> <span class="hljs-string">Everything</span> <span class="hljs-string">about</span> <span class="hljs-string">orders</span> <span class="hljs-attr">paths:</span> <span class="hljs-string">/products:</span> <span class="hljs-attr">get:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Return</span> <span class="hljs-string">all</span> <span class="hljs-string">products</span> <span class="hljs-attr">tags:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">Products</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-attr">description:</span> <span class="hljs-string">OK</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">schema:</span> <span class="hljs-string">ref:</span> <span class="hljs-string">'#/components/schemas/Product'</span> <span class="hljs-attr">post:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Add</span> <span class="hljs-string">a</span> <span class="hljs-string">product</span> <span class="hljs-attr">requestBody:</span> <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">schema:</span> <span class="hljs-string">$ref:</span> <span class="hljs-string">'#/components/schemas/Product'</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-attr">description:</span> <span class="hljs-string">OK</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">example:</span> <span class="hljs-attr">productId:</span> <span class="hljs-string">"123456"</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"Example Product"</span> <span class="hljs-attr">description:</span> <span class="hljs-string">"This is an example product"</span> <span class="hljs-attr">price:</span> <span class="hljs-number">19.99</span> <span class="hljs-string">/products/{id}:</span> <span class="hljs-attr">get:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Return</span> <span class="hljs-string">a</span> <span class="hljs-string">product</span> <span class="hljs-string">with</span> <span class="hljs-string">productId</span> <span class="hljs-attr">parameters:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">in:</span> <span class="hljs-string">path</span> <span class="hljs-attr">name:</span> <span class="hljs-string">id</span> <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">schema:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-att

Options

r">description:</span> <span class="hljs-string">OK</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">schema:</span> <span class="hljs-string">ref:</span> <span class="hljs-string">'#/components/schemas/Product'</span> <span class="hljs-attr">put:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Update</span> <span class="hljs-string">a</span> <span class="hljs-string">product</span> <span class="hljs-string">with</span> <span class="hljs-string">productId</span> <span class="hljs-attr">parameters:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">in:</span> <span class="hljs-string">path</span> <span class="hljs-attr">name:</span> <span class="hljs-string">id</span> <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">schema:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">requestBody:</span> <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">schema:</span> <span class="hljs-string">ref:</span> <span class="hljs-string">'#/components/schemas/Product'</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-attr">description:</span> <span class="hljs-string">OK</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">example:</span> <span class="hljs-attr">productId:</span> <span class="hljs-string">"123456"</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"Updated Product"</span> <span class="hljs-attr">description:</span> <span class="hljs-string">"This is an updated product"</span> <span class="hljs-attr">price:</span> <span class="hljs-number">24.99</span> <span class="hljs-attr">patch:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Partially</span> <span class="hljs-string">update</span> <span class="hljs-string">a</span> <span class="hljs-string">product</span> <span class="hljs-string">with</span> <span class="hljs-string">productId</span> <span class="hljs-attr">parameters:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">in:</span> <span class="hljs-string">path</span> <span class="hljs-attr">name:</span> <span class="hljs-string">id</span> <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">schema:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">requestBody:</span> <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">schema:</span> <span class="hljs-string">ref:</span> <span class="hljs-string">'#/components/schemas/Product'</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-attr">description:</span> <span class="hljs-string">OK</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">example:</span> <span class="hljs-attr">productId:</span> <span class="hljs-string">"123456"</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"Updated Product"</span> <span class="hljs-attr">delete:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Delete</span> <span class="hljs-string">a</span> <span class="hljs-string">product</span> <span class="hljs-string">with</span> <span class="hljs-string">productId</span> <span class="hljs-attr">parameters:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">in:</span> <span class="hljs-string">path</span> <span class="hljs-attr">name:</span> <span class="hljs-string">id</span> <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">schema:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-attr">description:</span> <span class="hljs-string">OK</span> <span class="hljs-string">/orders:</span> <span class="hljs-attr">get:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Return</span> <span class="hljs-string">all</span> <span class="hljs-string">orders</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-attr">description:</span> <span class="hljs-string">OK</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">example:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">orderId:</span> <span class="hljs-string">"789012"</span> <span class="hljs-attr">customerId:</span> <span class="hljs-string">"987654"</span> <span class="hljs-attr">products:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">productId:</span> <span class="hljs-string">"123456"</span> <span class="hljs-attr">quantity:</span> <span class="hljs-number">2</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">productId:</span> <span class="hljs-string">"789012"</span> <span class="hljs-attr">quantity:</span> <span class="hljs-number">1</span> <span class="hljs-attr">totalPrice:</span> <span class="hljs-number">59.97</span> <span class="hljs-attr">post:</span> <span class="hljs-attr">summary:</span> <span class="hljs-string">Add</span> <span class="hljs-string">an</span> <span class="hljs-string">order</span> <span class="hljs-attr">requestBody:</span> <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">schema:</span> <span class="hljs-string">ref:</span> <span class="hljs-string">'#/components/schemas/Order'</span> <span class="hljs-attr">responses:</span> <span class="hljs-attr">'200':</span> <span class="hljs-attr">description:</span> <span class="hljs-string">OK</span> <span class="hljs-attr">content:</span> <span class="hljs-attr">application/json:</span> <span class="hljs-attr">example:</span> <span class="hljs-attr">orderId:</span> <span class="hljs-string">"789012"</span> <span class="hljs-attr">customerId:</span> <span class="hljs-string">"987654"</span> <span class="hljs-attr">products:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">productId:</span> <span class="hljs-string">"123456"</span> <span class="hljs-attr">quantity:</span> <span class="hljs-number">2</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">productId:</span> <span class="hljs-string">"789012"</span> <span class="hljs-attr">quantity:</span> <span class="hljs-number">1</span> <span class="hljs-attr">totalPrice:</span> <span class="hljs-number">59.97</span> <span class="hljs-attr">components:</span> <span class="hljs-attr">schemas:</span> <span class="hljs-attr">Product:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">object</span> <span class="hljs-attr">properties:</span> <span class="hljs-attr">productId:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">example:</span> <span class="hljs-attr">name:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">description:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">price:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">number</span> <span class="hljs-attr">required:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">productId</span> <span class="hljs-bullet">-</span> <span class="hljs-string">name</span> <span class="hljs-bullet">-</span> <span class="hljs-string">description</span> <span class="hljs-bullet">-</span> <span class="hljs-string">price</span> <span class="hljs-attr">Order:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">object</span> <span class="hljs-attr">properties:</span> <span class="hljs-attr">orderId:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">customerId:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">products:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">array</span> <span class="hljs-attr">items:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">object</span> <span class="hljs-attr">properties:</span> <span class="hljs-attr">productId:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">string</span> <span class="hljs-attr">quantity:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span> <span class="hljs-attr">totalPrice:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">number</span> <span class="hljs-attr">required:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">orderId</span> <span class="hljs-bullet">-</span> <span class="hljs-string">customerId</span> <span class="hljs-bullet">-</span> <span class="hljs-string">products</span> <span class="hljs-bullet">-</span> <span class="hljs-string">totalPrice</span> <span class="hljs-attr">securitySchemes:</span> <span class="hljs-attr">ApiKeyAuth:</span> <span class="hljs-attr">type:</span> <span class="hljs-string">apiKey</span> <span class="hljs-attr">in:</span> <span class="hljs-string">header</span> <span class="hljs-attr">name:</span> <span class="hljs-string">X-API-Key</span></pre></div><h2 id="aff2">Swagger Editor</h2><p id="7324">If we want a UI to view our specification file, we can use <a href="https://editor.swagger.io/">Swagger Editor</a>. Just paste the content of your spec file and you’ll be able to view it.</p><figure id="a0f9"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*D0Aug-ZEBCEmoFBZS9Envw.png"><figcaption></figcaption></figure><p id="d799">There are also other editors and other ways to view your API’s documentation. For example, there is Redocly (and <a href="https://mediumapi.redoc.ly/">here</a> is an API doc I deployed with Redocly).</p><h2 id="a3c8">Final Note</h2><p id="160e">I hope this article has whetted your appetite for OpenAPI, because it’s a really good way of making clean code, and above all the visual interface is so handy for quickly testing your API.</p><p id="f5ae"><b>Thanks for reading! </b>Here are some links that may interest you:</p><ul><li><a href="https://readmedium.com/python-index-79257c082fe1">💻 All my tech articles</a></li><li><a href="https://readmedium.com/about-me-d63607c8c341"><i> Know more about me and my articles</i></a><i>!</i></li><li><a href="https://medium.com/subscribe/@estebanthi">🔔<i> Become an email subscriber</i></a><i>!</i></li><li><a href="https://medium.com/@estebanthi/membership">🤝<i> Support me by subscribing with my referal link</i></a><i>:</i></li></ul><div id="cdcb" class="link-block"> <a href="https://medium.com/@estebanthi/membership"> <div> <div> <h2>Join Medium with my referral link — Esteban Thilliez</h2> <div><h3>Read every story from Esteban Thilliez (and thousands of other writers on Medium). Your membership fee directly…</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*IoN4BofrwCNWA_bS)"></div> </div> </div> </a> </div></article></body>

What Is OpenAPI Specification? (And Why You Should Start Using It Now)

I’ve already built several APIs, yet I’d never heard of OpenAPI. I discovered it recently, and it’s a life-changer when it comes to building APIs.

If you don’t know what it is, this article is your chance to find out, and you’ll understand that there are only benefits to using the OpenAPI specification.

What is OpenAPI?

OpenAPI, is a specification for building and documenting web APIs. It provides a standardized way to describe the structure, operations, and interactions of an API, allowing developers to understand and work with the API without needing to inspect its underlying implementation details.

OpenAPI uses a machine-readable YAML or JSON format to define the API’s endpoints, request and response payloads, supported HTTP methods (such as GET, POST, PUT, DELETE), authentication requirements, and other relevant information. This specification acts as a contract between the API provider and consumers, ensuring consistency, clarity, and interoperability.

With an OpenAPI definition, you can automatically generate client SDKs, server stubs (more about this in another article), interactive API documentation, and perform validation and testing of API requests and responses. It fosters collaboration between frontend and backend developers, streamlines the development process, and allows for easier integration of APIs into various applications.

Additionally, OpenAPI provides tools and frameworks that support the full lifecycle of an API, from design and development to testing and deployment.

Why Use OpenAPI?

Before I knew about OpenAPI, I was doing my APIs a bit haphazardly. What’s more, they were rarely documented. Maybe it’s just me doing things badly, but in any case, using the OpenAPI specification allows me to impose a certain rigor on the APIs I make from now on, and to have an overview of the API before I start coding it.

On top of that, the tools offered by OpenAPI are quite practical, especially the ability to test your API via a graphical interface, which saves time and avoids having to copy all the requests to Postman.

Finally, all this leads to a code being cleaner when using OpenAPI specification.

Online Store API

Let’s imagine that we want to create an API for our online store so that we can add, modify and delete orders and products automatically. We have a rough idea of the requirements we need, but let’s write them down explicitly, along with the endpoints we will setup:

  • Return all products: GET /products
  • Add a product: POST /products
  • Return a product with productId: GET /products/{id}
  • Update a product with productId: PUT /products/{id}
  • Partially update a product with productId: PATCH /products/{id}
  • Delete a product with productId: DELETE /products/{id}
  • Return all orders: GET /orders
  • Add an order: POST /orders

There are obviously more in a real-life situation, but for the example it’s fine.

Now we have our endpoints, we want to define our objects.

Product object:

{
  "productId": "123456",
  "name": "Example Product",
  "description": "This is an example product",
  "price": 19.99,
}

Order object:

{
  "orderId": "789012",
  "customerId": "987654",
  "products": [
    {
      "productId": "123456",
      "quantity": 2
    },
    {
      "productId": "789012",
      "quantity": 1
    }
  ],
  "totalPrice": 59.97,
}

Now, our requirements are clearly defined, and we can create our OpenAPI file.

OpenAPI Syntax

I said earlier that the OpenAPI specification uses a YAML or JSON syntax to define the structure and details of an API. Here are some components of its syntax:

  • Info: This section contains general information about the API, such as its title, version, description, and contact details.
  • Paths: The “paths” section defines the available API endpoints and their associated operations. Each endpoint is represented by a URL path, and the supported HTTP methods (e.g., GET, POST, PUT, DELETE) are specified along with their corresponding request and response definitions.
  • Parameters: Parameters define the input values that can be passed to API operations. They can be query parameters, path parameters, header parameters, or request body parameters. Each parameter has properties like name, type, description, and whether it is required or optional.
  • Responses: The “responses” section describes the possible responses that an API endpoint can return. Each response is associated with an HTTP status code, such as 200 for a successful response or 404 for a not found response. The response definition may include the response body schema, headers, and descriptions.
  • Request and Response Bodies: OpenAPI allows you to specify the structure and format of request and response bodies using JSON Schema or other compatible formats. You can define the properties, types, formats, and validation rules for the data expected in the request payload or returned in the response.
  • Security: The “security” section enables you to define the security requirements for accessing the API endpoints. It includes authentication schemes, such as API keys, OAuth, or JWT, and specifies which endpoints require authentication and how it should be performed.
  • Tags: Tags are used to categorize and group related API endpoints. They provide a way to organize and navigate through the API documentation and can be helpful in large API specifications.

Creating our OpenAPI File

Now, let’s start creating our OpenAPI file. We name it openapi.yml (I’m using YAML, but you can use JSON if you want).

We first need to specify the OpenAPI version of the specification:

openapi: 3.0.0

We’ll use OpenAPI 3.0.0.

Then, we can specify our info component:

info:
  title: Example API
  version: 1.0.0

We can provide some more attributes such as description , contact , license , etc… But I will use only the main attributes, you can find the others in OpenAPI’s documentation

If we want to be able to try our API from a UI, we have to specify the servers component. This way we will have a button next to each endpoint to try it.

In this component, we can specify as many URLs as we want. When we will try an endpoint, it will send the corresponding request to the selected server.

servers:
  - url: https://localhost:8080/api

Then, we can specify our Productand Orderschemas. Schemas are just data types. They can be anything. Objects, arrays, primitives… It’s useful to specify them here so that we will be able to reference them later when specifying our endpoints.

Here is the syntax, it’s not difficult to understand I think so I let you with this:

components:
  schemas:
    Product:
      type: object
      properties:
        productId:
          type: string
        name:
          type: string
        description:
          type: string
        price:
          type: number
      required:
        - productId
        - name
        - description
        - price
    Order:
      type: object
      properties:
        orderId:
          type: string
        customerId:
          type: string
        products:
          type: array
          items:
            type: object
            properties:
              productId:
                type: string
              quantity:
                type: integer
        totalPrice:
          type: number
      required:
        - orderId
        - customerId
        - products
        - totalPrice

For each attribute, we can specify an example if we want:

components:
  schemas:
    Product:
      type: object
      properties:
        productId:
          type: string
          example: 123456
        name:
          type: string
          example: A product
        description:
          type: string
        price:
          type: number
      required:
        - productId
        - name
        - description
        - price

Specifying our Endpoints

To specify our endpoints, we need to add a paths object to our file. This object contains as many paths as you want, and a path object can contain each HTTP method.

OpenAPI 3.0 supports get, post, put, patch, delete, head, options, and trace.

OpenAPI defines operations as a combination of a path and a method. Then, each operation may have some attributes including description , summary , responses , parameters , etc…

Let’s start with our first operation: GET all products.

paths:
  /products:
    get:
      summary: Return all products
      responses:
        '200':
          description: OK
          content:
            application/json:
              example:
                - productId: "123456"
                  name: "Example Product"
                  description: "This is an example product"
                  price: 19.99

It takes no parameters and returns a list of products.

The responses object can contain as many responses as you want. Each response has a content and a description. You can specify an example in the content if you want. But you can also specify a schema, such as the schemas we’ve defined just before. And even better, you can add a reference to an existing schema:

paths:
  /products:
    get:
      summary: Return all products
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Product'

Now, imagine we want to add an operation that takes parameters. Let’s see how to do this:

  /products/{id}:
    get:
      summary: Return a product with productId
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Product'

Here, we’ve added the /products/{id} path. id is a parameter, so we should use brackets. Then, we add a parameters object containing the list of our parameters. Here, we just have one. We specify the location of the parameter (query, path…), its name, if it is required, and its schema. We can also add a description and an example if we want.

Now, let’s move on to an operation that requires a request body:

paths:
  /products:
    post:
      summary: Add a product
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Product'

We just add a requestBody object, specify whether it’s required, and its content.

Now, you know everything you need to know to add the remaining operations.

Security

We can add security schemes in the securitySchemes object. For example, if we want to secure our API with an API key:

  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

There are many authentication mechanisms available, check the doc for more details.

Tags

You can add tags if you want to organize your operations. First, add a tags object:

tags:
  - name: Products
    description: Everything about products
  - name: Orders
    description: Everything about orders

Then, add tags to operations:

paths:
  /products:
    get:
      summary: Return all products
      tags:
        - Products

Putting It All Together

Here is an example of a whole openapi.yaml file:

openapi: 3.0.0
info:
  title: Example API
  version: 1.0.0
servers:
  - url: https://localhost:8080/api
tags:
  - name: Products
    description: Everything about products
  - name: Orders
    description: Everything about orders
paths:
  /products:
    get:
      summary: Return all products
      tags:
        - Products
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Product'
    post:
      summary: Add a product
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Product'
      responses:
        '200':
          description: OK
          content:
            application/json:
              example:
                productId: "123456"
                name: "Example Product"
                description: "This is an example product"
                price: 19.99
  /products/{id}:
    get:
      summary: Return a product with productId
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Product'
    put:
      summary: Update a product with productId
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Product'
      responses:
        '200':
          description: OK
          content:
            application/json:
              example:
                productId: "123456"
                name: "Updated Product"
                description: "This is an updated product"
                price: 24.99
    patch:
      summary: Partially update a product with productId
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Product'
      responses:
        '200':
          description: OK
          content:
            application/json:
              example:
                productId: "123456"
                name: "Updated Product"
    delete:
      summary: Delete a product with productId
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
  /orders:
    get:
      summary: Return all orders
      responses:
        '200':
          description: OK
          content:
            application/json:
              example:
                - orderId: "789012"
                  customerId: "987654"
                  products:
                    - productId: "123456"
                      quantity: 2
                    - productId: "789012"
                      quantity: 1
                  totalPrice: 59.97
    post:
      summary: Add an order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Order'
      responses:
        '200':
          description: OK
          content:
            application/json:
              example:
                orderId: "789012"
                customerId: "987654"
                products:
                  - productId: "123456"
                    quantity: 2
                  - productId: "789012"
                    quantity: 1
                totalPrice: 59.97
components:
  schemas:
    Product:
      type: object
      properties:
        productId:
          type: string
          example: 
        name:
          type: string
        description:
          type: string
        price:
          type: number
      required:
        - productId
        - name
        - description
        - price
    Order:
      type: object
      properties:
        orderId:
          type: string
        customerId:
          type: string
        products:
          type: array
          items:
            type: object
            properties:
              productId:
                type: string
              quantity:
                type: integer
        totalPrice:
          type: number
      required:
        - orderId
        - customerId
        - products
        - totalPrice
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

Swagger Editor

If we want a UI to view our specification file, we can use Swagger Editor. Just paste the content of your spec file and you’ll be able to view it.

There are also other editors and other ways to view your API’s documentation. For example, there is Redocly (and here is an API doc I deployed with Redocly).

Final Note

I hope this article has whetted your appetite for OpenAPI, because it’s a really good way of making clean code, and above all the visual interface is so handy for quickly testing your API.

Thanks for reading! Here are some links that may interest you:

API
Programming
Development
Coding
Api Development
Recommended from ReadMedium