<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bump.sh</title>
    <description>The latest articles on DEV Community by Bump.sh (@bump_sh).</description>
    <link>https://dev.to/bump_sh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1085679%2F7b4dc40e-38da-40a2-8411-03b604c975bd.png</url>
      <title>DEV Community: Bump.sh</title>
      <link>https://dev.to/bump_sh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bump_sh"/>
    <language>en</language>
    <item>
      <title>JSON Streaming in OpenAPI 3.2</title>
      <dc:creator>Bump.sh</dc:creator>
      <pubDate>Tue, 02 Sep 2025 14:04:35 +0000</pubDate>
      <link>https://dev.to/bump/json-streaming-in-openapi-32-5dcl</link>
      <guid>https://dev.to/bump/json-streaming-in-openapi-32-5dcl</guid>
      <description>&lt;p&gt;Streaming data allows API servers to send and receive data in real-time or in chunks, rather than waiting for the entire response to be ready. This is already how browsers handle HTML, images, and other media, and now it can be done for APIs working with JSON.&lt;/p&gt;

&lt;p&gt;This can improve responses with lots of data, or be used to send events from server to client in realtime without polling or adding the complexity of Webhooks or WebSockets. Streaming works by sending "chunks", which clients can then work with individually instead of waiting for the entire response to be ready.&lt;/p&gt;

&lt;p&gt;Streaming JSON in particular is increasingly useful as expectations around big data, data science, and AI continue to grow. JSON on its own does not stream very well, but a few standards and conventions have popped up to expand JSON into a streamable format, and OpenAPI v3.2 introduces keywords to describe data in these stream formats.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON Streaming
&lt;/h2&gt;

&lt;p&gt;Streaming JSON is a bit tricky because JSON is not designed to be streamed. A naive approach might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1985-04-12T23:20:50.52Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hi!"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would trip up most tooling (because the closing bracket is not present in the payload), but we can use something like &lt;a href="https://jsonlines.org/" rel="noopener noreferrer"&gt;JSON Lines&lt;/a&gt; (a.k.a JSONL) to send one JSON instance per line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1985-04-12T23:20:50.52Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hi!"&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="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1985-04-12T23:20:51.37Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hows it hangin?"&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="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1985-04-12T23:20:53.29Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bye!"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This format allows each line to be a valid JSON object, making it easy to parse with standard native tooling and a &lt;code&gt;for&lt;/code&gt; loop. There are a bunch of other streaming formats you might want to work with in your API like &lt;a href="https://github.com/ndjson/ndjson-spec" rel="noopener noreferrer"&gt;Newline Delimited JSON&lt;/a&gt; (NDJSON), &lt;a href="https://www.rfc-editor.org/rfc/rfc7464.html" rel="noopener noreferrer"&gt;JSON Text Sequence&lt;/a&gt;, &lt;a href="https://datatracker.ietf.org/doc/html/rfc8142" rel="noopener noreferrer"&gt;GeoJSON Text Sequence&lt;/a&gt;. Thankfully they are all quite similar and working with them in OpenAPI is almost identical.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streaming with OpenAPI
&lt;/h2&gt;

&lt;p&gt;OpenAPI v3.0 &amp;amp; v3.1 were able to stream binary data, but struggled to support JSON streaming formats as there was no standard way to define the &lt;strong&gt;schema of individual events&lt;/strong&gt; in a stream. People would try to describe things as an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;application/jsonl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
      &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
        &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
            &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;date-time&lt;/span&gt;
          &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might see this sort of thing around, but it's not valid, and will confuse tooling. A stream cannot be described as a single array, and it is a sequence of multiple objects on new lines which is rather different. Some tools could spot the &lt;code&gt;application/jsonl&lt;/code&gt; content type and figure that out, but we don't need awkward hacks anymore because the OpenAPI team have solved the problem. &lt;/p&gt;

&lt;p&gt;OpenAPI v3.2 introduces two new keywords to describe streamed data and events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;itemSchema&lt;/code&gt; - define the structure of each item in a stream.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;itemEncoding&lt;/code&gt; - define how those items are encoded (or serialized), as text, JSON, binary, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  itemSchema
&lt;/h3&gt;

&lt;p&gt;Describing a stream with &lt;code&gt;itemSchema&lt;/code&gt; works just like &lt;code&gt;schema&lt;/code&gt; with one difference: it will be applied to each item in the stream, instead of the entire response.&lt;/p&gt;

&lt;p&gt;Consider an example like the &lt;a href="https://github.com/bump-sh-examples/train-travel-api/" rel="noopener noreferrer"&gt;train travel API&lt;/a&gt; running a stream of tickets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/jsonl; charset=utf-8
Transfer-Encoding: chunked
Date: Tue, 19 Aug 2025 18:36:10 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"train":"ICE 123","from":"Berlin","to":"Munich","price":79.9}
{"train":"TGV 456","from":"Paris","to":"Lyon","price":49.5}
{"train":"EC 789","from":"Zurich","to":"Milan","price":59}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To describe this stream of items, we can use the &lt;code&gt;itemSchema&lt;/code&gt; keyword:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;application/jsonl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;itemSchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;train&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
          &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;float&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tooling now has two important switches it can use to figure out how to handle the response. The &lt;code&gt;itemSchema&lt;/code&gt; makes it clear the response is a stream, and the &lt;code&gt;application/jsonl&lt;/code&gt; content type lets tooling decide how to present that.&lt;/p&gt;

&lt;p&gt;For streaming formats that just handle streams of JSON, the &lt;code&gt;itemSchema&lt;/code&gt; is often sufficient to describe the structure of each item in the stream. For more complicated formats, additional encoding information may be needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  itemEncoding
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;itemEncoding&lt;/code&gt; keyword allows you to specify how each item in the stream should be encoded, with the same encoding object as the &lt;code&gt;encoding&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;itemEncoding&lt;/code&gt; is only possible for &lt;code&gt;multipart/*&lt;/code&gt; responses, so it is not very useful for an API that's streaming JSON, unless you were streaming a mixture of JSON and assets/images on a single response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;multipart/mixed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;itemSchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;$comment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;A single data image from the device&lt;/span&gt;
    &lt;span class="na"&gt;itemEncoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contentType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;image/jpg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's ignore itemEncoding for now and focus on the major use case of streams for APIs: streaming data and events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Popular Streaming Formats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jsonlines.org/" rel="noopener noreferrer"&gt;JSON Lines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ndjson/ndjson-spec" rel="noopener noreferrer"&gt;NDJSON&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc7464" rel="noopener noreferrer"&gt;JSON Text Sequences&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events" rel="noopener noreferrer"&gt;Server-Sent Events (SSE)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They all work a little different, but they share the common goal of allowing data to be sent in a continuous stream rather than as a single, complete response.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON Lines &amp;amp; NDJSON
&lt;/h3&gt;

&lt;p&gt;Working with JSON Lines or NDJSON is basically identical in OpenAPI, and feels very much like working with plain JSON responses just with a different header and a bit of &lt;code&gt;itemSchema&lt;/code&gt; usage.&lt;/p&gt;

&lt;p&gt;If using JSONL use content type &lt;code&gt;application/jsonl&lt;/code&gt;, and if using NDJSON use content type &lt;code&gt;application/x-ndjson&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;/logs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Stream of logs as JSON Lines&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;200'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;A stream of JSON-format log messages that can be read&lt;/span&gt;
            &lt;span class="s"&gt;for as long as the application is running, and is available&lt;/span&gt;
            &lt;span class="s"&gt;in any of the sequential JSON media types.&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/jsonl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;itemSchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
                &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
                    &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;date-time&lt;/span&gt;
                  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
                    &lt;span class="na"&gt;minimum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
                  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
              &lt;span class="na"&gt;examples&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;JSONL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Log entries&lt;/span&gt;
                  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JSONL examples are just a string where each line is a valid JSON object.&lt;/span&gt;
                  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
                    &lt;span class="s"&gt;{"timestamp": "1985-04-12T23:20:50.52Z", "level": 1, "message": "Hi!"}&lt;/span&gt;
                    &lt;span class="s"&gt;{"timestamp": "1985-04-12T23:20:51.37Z", "level": 1, "message": "Hows it hangin?"}&lt;/span&gt;
                    &lt;span class="s"&gt;{"timestamp": "1985-04-12T23:20:53.29Z", "level": 1, "message": "Bye!"}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example once again shows JSONL as a series of JSON objects with a newline character &lt;code&gt;\n&lt;/code&gt; (0x0A) between them. This can only be described as a &lt;a href="https://yaml-multiline.info/" rel="noopener noreferrer"&gt;YAML multiline string&lt;/a&gt;, because JSONL/NDJSON cannot be described as plain JSON/YAML due to the newline characters.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember to use &lt;code&gt;value: |&lt;/code&gt; to write multi-line strings in YAML, because the pipe will allow newlines to be passed through. Using &lt;code&gt;value: &amp;gt;&lt;/code&gt; would remove newlines and put each JSON instance onto the same line. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The sample code for either of these formats could look a bit like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/tickets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/jsonl; charset=utf-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Transfer-Encoding&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chunked&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ticket&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;tickets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JSON Text Sequence
&lt;/h3&gt;

&lt;p&gt;A third JSON streaming format which would be identical other than a weird little complication. The other two formats are just a newline character &lt;code&gt;\n&lt;/code&gt; (0x0A) at the end of the line, but &lt;a href="https://www.rfc-editor.org/rfc/rfc7464.html" rel="noopener noreferrer"&gt;RFC 7464: JSON Text Sequence&lt;/a&gt; requires a control character at the start ASCII Record Separator (0x1E). This is not a visible character in most contexts, but it will be in there like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0x1E{"timestamp": "1985-04-12T23:20:50.52Z", "level": 1, "message": "Hi!"}
0x1E{"timestamp": "1985-04-12T23:20:51.37Z", "level": 1, "message": "Hows it hangin?"}
0x1E{"timestamp": "1985-04-12T23:20:53.29Z", "level": 1, "message": "Bye!"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;0x1E&lt;/code&gt; (ASCII Record Separator) indicates the start of a new JSON object in the stream. Control characters are a bit magical and invisible to most text editors so it can be a little confusing. Working with JSON Text Sequence tooling for both producing the stream and reading the stream can solve this problem, letting the tooling insert and read out the control characters without you needing to worry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Generator&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json-text-sequence&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ... snip express setup ...&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/tickets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json-seq&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ticket&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;tickets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://www.npmjs.com/package/json-text-sequence" rel="noopener noreferrer"&gt;json-text-sequence&lt;/a&gt; package makes this easier and provides a simple method for generating and consuming JSON Text Sequences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server-Sent Events (SSE)
&lt;/h3&gt;

&lt;p&gt;Streaming JSON as chunks of data is only one way that JSON gets streamed. What about sending events, with some JSON being passed along as attributes?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events" rel="noopener noreferrer"&gt;Server-Sent Events&lt;/a&gt; (SSE) can handle this, as a standard for sending real-time updates from a server to a client over HTTP. In OpenAPI, you can define SSE streams using the &lt;code&gt;text/event-stream&lt;/code&gt; content type and the &lt;code&gt;itemSchema&lt;/code&gt; keyword to describe the structure of the events being sent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;A request body to add a stream of typed data.&lt;/span&gt;
  &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;text/event-stream&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;itemSchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
        &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
          &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
          &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;event&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# Define event types and specific schemas for the corresponding data&lt;/span&gt;
        &lt;span class="na"&gt;oneOf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;const&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;addString&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;const&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;addInt64&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;int64&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;const&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;addJson&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;contentMediaType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
              &lt;span class="na"&gt;contentSchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
                &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
                &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;oneOf&lt;/code&gt; is optional, but a handy use of &lt;a href="//_guides/openapi/specification/v3.2/data-models/schema-composition.md"&gt;polymorphism&lt;/a&gt; to describe different schemas for each event - which can really help with documentation and validation.&lt;/p&gt;

&lt;p&gt;Valid events to come through this stream might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;event: addString
data: This data is formatted
data: across two lines
retry: 5

event: addInt64
data: 1234.5678
unknownField: this is ignored

event: addJSON
data: {"foo": 42}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sentinel Events
&lt;/h2&gt;

&lt;p&gt;Some streaming systems do not always send all data or events in the exact same way. The items in a stream could be polymorphic objects, or there could be some special events that come through to say the stream is closed (also known as sentinel events).&lt;/p&gt;

&lt;p&gt;Instead of trying to handle all of these edge cases with special new keywords, OpenAPI allows you to use the standard JSON Schema keywords to model these variations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;text/event-stream&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;itemSchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;oneOf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your normal data/event schema&amp;gt;&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;const&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[DONE]"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whatever the schema is, it can be defined using the standard JSON Schema keywords like &lt;code&gt;oneOf&lt;/code&gt;, &lt;code&gt;anyOf&lt;/code&gt;, or &lt;code&gt;allOf&lt;/code&gt; to handle variations in the event structure. This allows you to define a flexible schema that can accommodate different types of events in the stream.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We're excited for OpenAPI v3.2 to launch (hopefully any time in the next few weeks?) and we're working hard to get Bump.sh ready to support as much of &lt;a href="//_posts/2025-07-22-openapi-3-2-what-to-expect.md"&gt;the new functionality&lt;/a&gt; as possible. Let us know in the comments what features you're looking forward to, and share any ideas you have for how we can improve our support for streaming JSON in APIs.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Top 5 API documentation tools</title>
      <dc:creator>Bump.sh</dc:creator>
      <pubDate>Wed, 11 Jun 2025 15:52:48 +0000</pubDate>
      <link>https://dev.to/bump/top-5-api-documentation-tools-4nj6</link>
      <guid>https://dev.to/bump/top-5-api-documentation-tools-4nj6</guid>
      <description>&lt;p&gt;Without documentation nobody knows an API exists or how to use it, so it’s worth investing the time in creating clear, useful, understandable documentation. This will help customers integrate with their applications quicker, cut down on support calls, and allow coworkers to onboard quicker as they join the company or move teams.&lt;/p&gt;

&lt;p&gt;Fully documenting an API can be a long and difficult process, but new tools are always popping aiming to solve the problem in different ways. Some are open-source and some are Software-as-a-Service, some focus on beautiful interfaces, some focus on powerful functionality, and some focus on jamming AI all over the place.&lt;/p&gt;

&lt;p&gt;There’s no one tool to rule them all, and different tools may be chosen depending on who is in charge of setting up the documentation (API developers, technical writers, governance teams) and the intended audience (public APIs, internal APIs, partner APIs).&lt;/p&gt;

&lt;p&gt;There’s also the question of if this is for a single API or multiple APIs, whether or not other types of guides are supported (often via Markdown), and whether they support API discoverability through API catalogs to help customers pick between those various APIs or if you need to build that yourself.&lt;/p&gt;

&lt;p&gt;To learn which documentation tools can be helpful for different scenarios, let’s compare the most popular OpenAPI documentation tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bump.sh&lt;/li&gt;
&lt;li&gt;Redoc&lt;/li&gt;
&lt;li&gt;Scalar&lt;/li&gt;
&lt;li&gt;Stoplight Elements&lt;/li&gt;
&lt;li&gt;ReadMe.io&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bump.sh
&lt;/h2&gt;

&lt;p&gt;Bump.sh is a SaaS solution focused on building “Stripe-like” three column API reference documentation from OpenAPI and AsyncAPI documents from any source, using any workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44viyantud9evtrz7zm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44viyantud9evtrz7zm1.png" alt="Screenshot of Bump UI" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bump.sh focuses on getting out of your way, staying clear of the “Walled Garden” approach others take. Instead of forcing everything to be done through a very specific way through a user interface, it integrates with existing Git/CI workflows, providing useful insight through their automatic changelog and breaking change detection in pull requests. It’s also one of the first few tools to support AsyncAPI as well as OpenAPI, allowing for event-driven APIs to be documented along side the usual REST/HTTP APIs.&lt;/p&gt;

&lt;p&gt;API Catalogs are a strong feature known as Hubs, which allow for multiple APIs to be deployed from a variety of Git repos, or you can get creative with CI/CLI/API integrations to bring in API descriptions for anywhere. This is brilliant for large organizations trying to bring all their APIs into one place, even if teams have wildly different workflows, directory structures, design-first/code-first, spread around different GitHub/GitLab/Azure workspaces, and even allows for some older groups still using Subversion for some reason. This is the only tool compared which allows for this flexible approach to API catalogs. With different “Guests” able to view each Hub, this is brilliant for Partner APIs, especially as they can subscribe to API changes to be alerted of anything they need to know about directly.&lt;/p&gt;

&lt;p&gt;The brand new API Explorer has brought powerful Try It functionality to documentation which people are coming to expect in all API docs, with a dedicated UI for building requests. This improves the UX compared to some competitors which try to handle this all through the main documentation view, because that gets pretty crowded when there are a lot of parameters to set on any given request. To avoid losing track of the docs, the try it allows them to pop up in a side pane, allowing for quick reference during request construction.&lt;/p&gt;

&lt;p&gt;Multiple branches and versioning also make Bump.sh a great option for teams working on Public APIs where multiple versions of API documentation need to be maintained.&lt;/p&gt;

&lt;p&gt;The team pride themselves on availability, and zero chatbots or automation between you and getting an answer from a friendly dedicated technical support staff member. They’re real people working on making real software and not trying to game anything with AI.&lt;/p&gt;

&lt;p&gt;Bump.sh is free for 1 API, going up to €249/mo for multiple APIs, and an Enterprise option which focuses on tackling more complex needs and deep UI and UX integration into existing CMS’s using far more useful enterprise solutions than the usual JavaScript-widget approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ Version control-focused API documentation.&lt;/p&gt;

&lt;p&gt;✅ Blazing fast load times thanks to scanning OpenAPI / AsyncAPI changes and serving the results, instead of processing documents on-the-fly every time.&lt;/p&gt;

&lt;p&gt;✅ SEO-friendly thanks to the pre-rendered crawlable documentation.&lt;/p&gt;

&lt;p&gt;✅ Automatically detects and highlights API changes.&lt;/p&gt;

&lt;p&gt;✅ Supports AsyncAPI, OpenAPI 3.1, 3.0 &amp;amp; 2.0, Webhooks, and Overlays.&lt;/p&gt;

&lt;p&gt;✅ Enterprise: Can be run as .com/docs/* thanks to proxy support.&lt;/p&gt;

&lt;p&gt;✅ Enterprise: Can be embedded with custom header/footer with server-side rendered content for maximum SEO/crawler-friendly docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;❌ Cloud hosted only, no self-hosted or open-source options.&lt;/p&gt;

&lt;p&gt;❌ CSS maintenance is done by Bump.sh (no conventional customization/theming), yet brought a level higher with the Embedded mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CI/CD-focused teams integrating API documentation into DevOps workflows or docs-as-code workflows.&lt;/li&gt;
&lt;li&gt;Anyone trying to avoid being stuck in a walled garden. Your Git/CI is the source of truth.&lt;/li&gt;
&lt;li&gt;Teams working with complex API ecosystems, whether because multiple APIs, multiple API versions, many endpoints, deeply detailed objects, and/or fast evolving APIs.&lt;/li&gt;
&lt;li&gt;Tech reviewers eager for breaking change detection and API diffs to save them staring at a wall of potentially irrelevant YAML changes.&lt;/li&gt;
&lt;li&gt;Redoc&lt;/li&gt;
&lt;li&gt;Redoc is an old champion in the OpenAPI documentation world, built by Redocly to offer a beautiful “Stripe-like” two or three panel experience back when the only real choice was the less appealing Swagger UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Screenshot of Redoc UI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Redoc is also available as a self-hosted/open-source option, and a hosted version is available as part of a larger SaaS platform Realm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftlx0dksjbeefawwg6fzx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftlx0dksjbeefawwg6fzx.png" alt="Screenshot of Redoc UI" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Self-hosted Redoc only displays one API at a time, meaning anyone with multiple APIs is going to need to build their own developer experience hubs using CMS’, documentation tools, or custom coded solutions if they want coherent navigation between them all.&lt;/p&gt;

&lt;p&gt;The hosted Redoc on the $10/month Pro allows for multiple APIs but only within a single project, which means work needs to be done to get multiple OpenAPI documents into that project instead of supporting multiple APIs in multiple sources.&lt;/p&gt;

&lt;p&gt;The $24/month Enterprise plan comes with SSO for managing who can edit APIs, and “guest SSO” for hiding the resulting API documentation which is handy for partner APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ Highly customizable, professional-looking UI.&lt;/p&gt;

&lt;p&gt;✅ Supports AsyncAPI, and OpenAPI 3.1, 3.0, and 2.0.&lt;/p&gt;

&lt;p&gt;✅ Can be self-hosted or used as a cloud service.&lt;/p&gt;

&lt;p&gt;✅ Includes “Try It” functionality on the cloud version.&lt;/p&gt;

&lt;p&gt;✅ Provides API governance through the hosted version, and a handy linting and bundling CLI tool.&lt;/p&gt;

&lt;p&gt;✅ Supports developer portal through Realm and Reunite SaaS products.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;❌ Requires some developer effort for customization.&lt;/p&gt;

&lt;p&gt;❌ No Try It on the self-hosted version.&lt;/p&gt;

&lt;p&gt;❌ Configuration is all done with YAML.&lt;/p&gt;

&lt;p&gt;❌ Builds interface on-the-fly by reading an OpenAPI document so large APIs load slowly.&lt;/p&gt;

&lt;p&gt;❌ Hosted version suffers very slow server-side rendering too.&lt;/p&gt;

&lt;p&gt;❌ Only add one Guest SSO identity provider per organization making partner APIs for multiple organizations difficult.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open-source API maintainers looking for a solid off-the-shelf open-source API documentation solution (self-hosted version).&lt;/li&gt;
&lt;li&gt;Teams who don’t mind writing some code to get highly customizable self-hosted API documentation, especially if trying to embed into existing CMS’ (self-hosted version).&lt;/li&gt;
&lt;li&gt;Publishing high quality reference documentation and guides for a single partner on an easily sharable link when no existing developer experience hubs exist (SaaS version).&lt;/li&gt;
&lt;li&gt;Scalar&lt;/li&gt;
&lt;li&gt;Scalar is made by developers, for developers, and you can tell. From the heavy focus on open-source tooling, to the dark-mode default with small text, and use of JetBrains Mono font, a quick glance at Scalar screams “programmers were here”.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scalar UI
&lt;/h2&gt;

&lt;p&gt;The toolsuite is very new, with a crux of their effort going into low-level open-source tooling to lay a groundwork for the rest of their tools to build upon. The nascent nature of their offering and their OSS focus doesn’t place them as a go-to solution for Enterprise customers who need more dedicated assistance, but their integration with open-source projects like Gitbook, Nitro, and Rust will make it a good choice for users of those tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccfgim15o7ux5kuu8v2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccfgim15o7ux5kuu8v2g.png" alt="Screenshot of Scalar UI" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ A drop-in replacement for single developers and small teams switching away from SwaggerHub, replacing Swagger UI &amp;amp; Swagger Editor.&lt;/p&gt;

&lt;p&gt;✅ Supports OpenAPI 3.1, 3.0, and 2.0.&lt;/p&gt;

&lt;p&gt;✅ All versions of Scalar support a powerful Try It / API client.&lt;/p&gt;

&lt;p&gt;✅ Cloud version has a built in text-based OpenAPI editor which handles small single-file OpenAPI documents.&lt;/p&gt;

&lt;p&gt;✅ Supports guides as well as reference documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;❌ Customization and theming focuses mostly on color schemes and custom CSS.&lt;/p&gt;

&lt;p&gt;❌ Editor does not support external references.&lt;/p&gt;

&lt;p&gt;❌ Doesn’t offer advanced API governance tools.&lt;/p&gt;

&lt;p&gt;❌ Builds interface on-the-fly by reading an OpenAPI document so large APIs load slowly.&lt;/p&gt;

&lt;p&gt;❌ Free SaaS only gets one user, then its $12/seat, with SSO behind a “Talk to the CEO” button.&lt;/p&gt;

&lt;p&gt;❌ GitHub Sync only available on Pro, with no other way to deploy via CLI or CI/CD.&lt;/p&gt;

&lt;p&gt;❌  Supports multiple APIs but no API Catalog / Dev Portal functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solo API developers who want a desktop HTTP client which happens to also produce API documentation.&lt;/li&gt;
&lt;li&gt;Open-source tools (e.g. web application frameworks, content management systems) which could themselves be self-hosted with an API and generate API endpoints / OpenAPI. Scalar would help turn that users generated OpenAPI into API documentation for their end-users without any SaaS involved.&lt;/li&gt;
&lt;li&gt;Stoplight Elements&lt;/li&gt;
&lt;li&gt;Stoplight Elements is a Web/React component that drops into existing documentation or open-source, allowing anyone to enjoy Stripe-like API documentation. It focuses on being as beautiful as possible, whilst still delivering the same functionality and covering the same use cases as Swagger UI. The tool was aiming to knock Swagger UI off the “top spot” years back, but active development has slowed to a crawl in a plume of irony after Swagger UI owners SmartBear bought Stoplight. It’s getting bug fixes and a handful of tweaky features, and development may well pick up again in the future, so it’s not out of the game just yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stoplight Elements UI
&lt;/h2&gt;

&lt;p&gt;The self-hosted tool can take any OpenAPI document by URL or path, but can only handle one API at a time like most of the self-hosted tools. There is an extension called Elements DevPortal, which can handle multiple APIs and Markdown guides, but this assumes all the APIs are in the same Stoplight Platform “project”. It’s essentially a mini API Catalog, but the catalog cannot pull OpenAPI/Markdown content out of multiple projects or repos making the catalog functionality a little limited.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xhd27ool4uk7iimnki7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xhd27ool4uk7iimnki7.png" alt="Screenshot of Stoplight Elements UI" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ Beautiful, interactive documentation with Try-It functionality.&lt;/p&gt;

&lt;p&gt;✅ Supports OpenAPI 3.1, 3.0, and 2.0.&lt;/p&gt;

&lt;p&gt;✅ Easy integration into existing documentation or apps via Web/React components.&lt;/p&gt;

&lt;p&gt;✅ Integrates with Stoplight Platform, a SaaS ecosystem which includes a GUI for API design, and API governance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;❌ Limited out-of-the-box customization compared to Redocly.&lt;/p&gt;

&lt;p&gt;❌ Confusing to get started for non technical users as it needs a web server and code to load the component.&lt;/p&gt;

&lt;p&gt;❌ Stoplight’s full suite can be expensive, with unlimited APIs/projects but paying per user.&lt;/p&gt;

&lt;p&gt;❌ Builds interface on-the-fly by reading an OpenAPI document so large APIs load slowly.&lt;/p&gt;

&lt;p&gt;❌ No API catalog functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams already using Stoplight for API design.&lt;/li&gt;
&lt;li&gt;Companies that prefer embedding documentation within existing apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ReadMe
&lt;/h2&gt;

&lt;p&gt;ReadMe is a hosted developer portal which allows for API documentation in all forms, not just API reference documentation, but supports Markdown guides and even Recipes for documenting workflows and breaking down code samples.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3mq4ge45sgko8bbs95s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3mq4ge45sgko8bbs95s.png" alt="Screenshot of ReadMe UI" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of deploying changes from a Git repository or providing an editor to make changes directly, there is a two-way sync to merge in changes.&lt;/p&gt;

&lt;p&gt;ReadMe is a strong pick for DevRel teams as it has built-in support for user feedback, a discussion forum, and tracks analytics. This can allow for data-driven improvements to the developer experience.&lt;/p&gt;

&lt;p&gt;The pricing starts off ok for startups at $99/month, but ramps up quickly to $399/month for custom CSS/HTML. Extras send the price even higher, with $100/month for developer dashboards. and another $150/month to enable a ChatGPT-enabled “Owlbot” taking a punt at answering questions with what might even occasionally be correct answers sometimes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ Provides interactive API docs with an API explorer.&lt;/p&gt;

&lt;p&gt;✅ Includes a developer portal with guides and tutorials.&lt;/p&gt;

&lt;p&gt;✅ User feedback and discussions.&lt;/p&gt;

&lt;p&gt;✅ Great for SaaS companies offering public APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;❌ Pricing can be high for startups.&lt;/p&gt;

&lt;p&gt;❌ Cloud hosted only, no self-hosted or open-source options.&lt;/p&gt;

&lt;p&gt;❌ Less control over the doc styling compared to self-hosted solutions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams that need API documentation and developer engagement tools.&lt;/li&gt;
&lt;li&gt;Businesses that want built-in analytics and API usage tracking.&lt;/li&gt;
&lt;li&gt;Recommendations&lt;/li&gt;
&lt;li&gt;So which is the best tool? As always “it depends”, so here are some quick pointers to help find the right tool for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When it comes to API docs, there’s no shortage of options, and no single right answer for every team.&lt;/p&gt;

&lt;p&gt;If you care about performance and SEO Bump.sh is the right pick.&lt;/p&gt;

&lt;p&gt;If you’re looking for a tool that fits cleanly into a modern, Git-based workflow, scales across multiple APIs and teams, and doesn’t lock you into yet another platform, Bump.sh has your back.&lt;/p&gt;

&lt;p&gt;Bump.sh is built for engineers and tech writers who want docs to ship like code: fast, versioned, and CI-integrated. It handles the messy reality of modern API ecosystems (REST, event-driven, partners, multiple teams, multiple repos) and turns that into a clean, scalable developer experience.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>OpenAPI 3.1 - The Cheat Sheet</title>
      <dc:creator>Bump.sh</dc:creator>
      <pubDate>Wed, 18 Sep 2024 15:09:40 +0000</pubDate>
      <link>https://dev.to/bump/openapi-31-the-cheat-sheet-c9l</link>
      <guid>https://dev.to/bump/openapi-31-the-cheat-sheet-c9l</guid>
      <description>&lt;p&gt;We can't tell you how stoked we are about this. It's been a while that we realized something key was missing, to help the entire community adopt and use &lt;a href="https://bump.sh/openapi" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt; daily.&lt;/p&gt;

&lt;p&gt;Something short enough, while thorough enough, so that you always make sure you always completely describe your API, without missing any crucial information, nor wondering "Hugh... How do I write this again?" and having to scan through the entire specification.&lt;/p&gt;

&lt;p&gt;Something you could even hold in your hands. Because, yes, as much as we avoid printing things on a day-to-day basis, sometimes screens are not enough. Teachers, rest assured: our cheat sheet print-outs are too large to be hidden in your students pockets.&lt;/p&gt;

&lt;p&gt;Anyway, that's it, we made it. Let us introduce the OpenAPI 3.1 Cheat Sheet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcn8aj3wkovvh9i9lhfb3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcn8aj3wkovvh9i9lhfb3.png" alt="Image description" width="800" height="565"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://storage.googleapis.com/bump-blog-resources/openapi-31-cheasheet/openapi-31-cheatsheet-v1.pdf" rel="noopener noreferrer"&gt;Download the PDF version&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It took us about 6 months to produce this first version. First of all, because we're of course quite busy developing Bump.sh and serving our customers. But more importantly, because synthesizing OpenAPI on an A4/US letter sheet is just not trivial.&lt;/p&gt;

&lt;p&gt;The Specification covers a wide range of use cases. It is robust in the sense that your APIs can be completely described, so that humans and machines alike can discover it, and interact with it. In the end, an OpenAPI contract can become quite deep and complex. We wanted to squeeze the essence out of it, and brainstormed multiple times about what should be in (and how), and what should be out.&lt;/p&gt;

&lt;p&gt;You'll read it on your own, but here are the sections we retained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.bump.sh/guides/openapi/specification/v3.1/understanding-structure/basic-structure/" rel="noopener noreferrer"&gt;Document Structure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.bump.sh/guides/openapi/specification/v3.1/understanding-structure/basic-structure/#2-info-object" rel="noopener noreferrer"&gt;General Information&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.bump.sh/guides/openapi/specification/v3.1/understanding-structure/paths-operations/" rel="noopener noreferrer"&gt;API Structure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.bump.sh/guides/openapi/specification/v3.1/data-models/schema-and-data-types/" rel="noopener noreferrer"&gt;Data Types and Schemas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.bump.sh/guides/openapi/specification/v3.1/advanced/security/" rel="noopener noreferrer"&gt;Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.bump.sh/guides/openapi/specification/v3.1/advanced/splitting-documents-with-ref/" rel="noopener noreferrer"&gt;Reuse Elements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.bump.sh/guides/openapi/specification/v3.1/data-models/schema-composition/" rel="noopener noreferrer"&gt;Polymorphism&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.bump.sh/guides/openapi/specification/v3.1/documentation/grouping-operations-with-tags/" rel="noopener noreferrer"&gt;Grouping and sorting&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We had a chance to work on this with OpenAPI experts (👋 Phil Sturgeon, James Higginbotham and Kin Lane, as well as some of our key power users at Elastic, Lightspeed Commerce, and many more).&lt;/p&gt;

&lt;p&gt;And we wanted to make the outcome of that work accessible completely for free, as the entire OpenAPI community should benefit from it, free of charge. It is &lt;a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en" rel="noopener noreferrer"&gt;CC BY-NC-SA 4.0 licensed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To be honest and transparent, this is a first version of that Cheat Sheet. We might have been a little too enthusiastic to print it for apidays London 2024. Fetch your exclusive sample there: there won't be many, and we'll have to print new versions for Paris as we've already spotted some typos.&lt;/p&gt;

&lt;p&gt;They're fixed in the downloadable PDF version, but if you have a hard copy and spot those errors, we're paying a drink to the first 5 people who drop by our booth with the full list of errors.&lt;/p&gt;

&lt;p&gt;This Cheat Sheet will be lively in the coming weeks and months. We'll work on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;improving the current version&lt;/li&gt;
&lt;li&gt;making a web version of it&lt;/li&gt;
&lt;li&gt;covering the next versions of OpenAPI (Moonwalk, we see you)&lt;/li&gt;
&lt;li&gt;making one for AsyncAPI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Share it with your network, the person working next to you or the world via social media; it's built for that!&lt;/p&gt;

</description>
      <category>api</category>
      <category>openapi</category>
    </item>
    <item>
      <title>An AsyncAPI Example: Building Your First Event-driven API</title>
      <dc:creator>Bump.sh</dc:creator>
      <pubDate>Tue, 19 Sep 2023 08:44:20 +0000</pubDate>
      <link>https://dev.to/bump/an-asyncapi-example-building-your-first-event-driven-api-37jo</link>
      <guid>https://dev.to/bump/an-asyncapi-example-building-your-first-event-driven-api-37jo</guid>
      <description>&lt;p&gt;Event-driven APIs are APIs that use events to enable real-time and asynchronous communication between different components of a system. This leads to a couple significant benefits right out of the gate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clients receive real-time updates without constantly polling the server, which improves user experience.&lt;/li&gt;
&lt;li&gt;System components can communicate without being directly connected to each other, so API producers and consumers can be more loosely coupled.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Use Event-driven APIs?
&lt;/h2&gt;

&lt;p&gt;Let’s break those two ideas down a bit so you can really see what’s going on.&lt;/p&gt;

&lt;p&gt;An &lt;em&gt;event&lt;/em&gt; is any change in state or an update that a client might be interested in, like a new user registration or an update in the payment status of a transaction. In an event-driven system, a component known as the &lt;em&gt;publisher&lt;/em&gt; sends an event to a message broker. The message broker sends the event to all the other components, known as &lt;em&gt;subscribers&lt;/em&gt;, that have registered to receive that particular event. This allows the components of the system to communicate in real-time without being directly connected to each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4ncnxk0xo7vzlg5vbgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4ncnxk0xo7vzlg5vbgg.png" alt="Event Driven Architecture" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As an example, picture a chat application. When a user sends a message, an event-driven API can immediately notify all the other users in the chat, allowing the message to display in their chat window without needing to refresh the page. In a traditional synchronous API, the client would need to poll the server to check for new messages very often and then update the user.  With event-driven APIs, clients receive real-time updates from the API without constantly polling for changes, making them more efficient when it comes to network resource usage. &lt;/p&gt;

&lt;p&gt;In a traditional synchronous request-response API, the components are tightly coupled. The consumer must make a request to the provider to receive data (say, for example, polling for new messages in a chat application). In an event-driven API, the components are decoupled. The publisher sends events to the message broker, which then broadcasts the events to the subscribers. The separate components can be more independent and flexible, since they don’t rely on direct communication with each other. &lt;/p&gt;

&lt;p&gt;However, in order for the system to work effectively, there must be a common understanding between the components regarding events and their data structures. This is where &lt;a href="https://www.asyncapi.com/" rel="noopener noreferrer"&gt;AsyncAPI&lt;/a&gt; comes in; it helps define a &lt;a href="https://bump.sh/blog/api-contracts-extended-introduction" rel="noopener noreferrer"&gt;contract&lt;/a&gt; that describes how the components communicate and behave effectively.&lt;/p&gt;

&lt;p&gt;Let’s walk through the process of implementing an event-driven API using AsyncAPI, a specification for defining asynchronous APIs. We’ll also introduce &lt;a href="https://bump.sh/" rel="noopener noreferrer"&gt;Bump.sh&lt;/a&gt;, a tool for documenting and tracking event-driven APIs lifecycle/changes, and demonstrate how you can use it in conjunction with AsyncAPI files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing a Node.js Event-Driven API with AsyncAPI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.asyncapi.com/" rel="noopener noreferrer"&gt;AsyncAPI&lt;/a&gt; is a specification for defining the structure and behavior of event-driven APIs. It’s &lt;a href="https://www.asyncapi.com/blog/openapi-vs-asyncapi-burning-questions" rel="noopener noreferrer"&gt;similar to OpenAPI&lt;/a&gt;, a specification for defining REST APIs.&lt;/p&gt;

&lt;p&gt;However, AsyncAPI has specific features for defining the events and subscriptions of an event-driven API. It provides a standardized way to describe the events, channels, and message formats used in an asynchronous API, making it easier for developers to understand and use that API. &lt;/p&gt;

&lt;p&gt;Before we begin the process of implementing a Node.js event-driven API described using AsyncAPI, there are a few prerequisites that you will need to have installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;Git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional:&lt;/strong&gt; &lt;a href="https://mosquitto.org/" rel="noopener noreferrer"&gt;Mosquitto&lt;/a&gt;, an open-source message broker that                 implements the &lt;a href="https://mqtt.org/mqtt-specification/" rel="noopener noreferrer"&gt;MQTT protocol&lt;/a&gt;; this tutorial uses the &lt;a href="%E2%80%8B%E2%80%8Bhttps://test.mosquitto.org/"&gt;public test server&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have these installed, you can follow the steps below to implement your event-driven API.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create an AsyncAPI File
&lt;/h3&gt;

&lt;p&gt;First, create an AsyncAPI file. This will define the events and their corresponding data that you’ll use in your event-driven system. It also defines the structure and behavior of your asynchronous APIs.&lt;/p&gt;

&lt;p&gt;AsyncAPI files are written in YAML or JSON and follow a specific format defined by the &lt;a href="https://www.asyncapi.com/docs/reference" rel="noopener noreferrer"&gt;AsyncAPI specification&lt;/a&gt;. An AsyncAPI file consists of several main components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;asyncapi&lt;/code&gt;: Specifies the version of the AsyncAPI specification that the file follows; at time of writing, the latest available is v2.6.0, which is what this tutorial uses.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;info&lt;/code&gt;: Contains metadata about the API, such as the &lt;code&gt;title&lt;/code&gt;,  the &lt;code&gt;version&lt;/code&gt; or the &lt;code&gt;description&lt;/code&gt; of your API.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.asyncapi.com/docs/concepts/server" rel="noopener noreferrer"&gt;&lt;code&gt;servers&lt;/code&gt;&lt;/a&gt;: Lists the servers that the API is available on, along with the protocol and any additional configuration required to use the server. In our testing API, that will be the network location of our message broker.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.asyncapi.com/docs/concepts/channel" rel="noopener noreferrer"&gt;&lt;code&gt;channels&lt;/code&gt;&lt;/a&gt;: Defines the channels that the API exposes, along with the operations that can be performed on each channel.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;components&lt;/code&gt;: Defines reusable components that can be used throughout the AsyncAPI file, such as &lt;a href="https://www.asyncapi.com/docs/concepts/message" rel="noopener noreferrer"&gt;message&lt;/a&gt; payloads and security schemes. This section is optional, as you can define these components directly, but I do recommend it. As your AsyncAPI definition file starts to grow, this helps you avoid repeating yourself (e.g., when a message format is used in multiple channels).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The snippet below defines the first part of the AsyncAPI file for a chat application. It covers the general application descriptions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;asyncapi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2.6.0&lt;/span&gt;
&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Chat Application&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.0&lt;/span&gt;
&lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;testing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test.mosquitto.org:1883&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mqtt&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test broker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This AsyncAPI file defines a chat application using the AsyncAPI 2.6.0 version.&lt;/p&gt;

&lt;p&gt;It also defines the &lt;code&gt;servers&lt;/code&gt; block that specifies the network location of your message broker. The API application defined here uses the MQTT protocol and is available on the testing server at &lt;code&gt;test.mosquitto.org:1883&lt;/code&gt;. This URL is a publicly available Mosquitto broker for test purposes; feel free to replace it with a local URL if you have Mosquitto installed on your environment.&lt;/p&gt;

&lt;p&gt;The following section defines the channels available within the API. It defines the different operations the chat application can perform and their payloads.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;channels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;onMessageReceieved&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;text&lt;/span&gt;
        &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;subscribe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sendMessage&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;text&lt;/span&gt;
        &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The channels section defines all the channels that the API exposes. In this case, there is a single channel called &lt;code&gt;chat&lt;/code&gt; that exposes a &lt;code&gt;publish&lt;/code&gt; and &lt;code&gt;subscribe&lt;/code&gt; operation. The &lt;code&gt;publish&lt;/code&gt; method allows clients to send messages to the chat application via the &lt;code&gt;chat&lt;/code&gt; channel, while the &lt;code&gt;subscribe&lt;/code&gt; method allows users to receive messages from the &lt;code&gt;chat&lt;/code&gt; channel.&lt;/p&gt;

&lt;p&gt;This might seem a bit counterintuitive as there are two sides to think about, the server application and the client. Instead, think about it this way: publish events are sent from the client to the application, while subscribe events are sent from the application to the clients.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read more about &lt;a href="https://www.asyncapi.com/blog/publish-subscribe-semantics" rel="noopener noreferrer"&gt;pub-sub semantics here&lt;/a&gt;, then check out &lt;a href="https://github.com/asyncapi/spec/issues/618" rel="noopener noreferrer"&gt;this proposal&lt;/a&gt; that aims to resolve the confusion between publish and subscribe events. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the case of this tutorial, both operations have a very simple message payload of type &lt;code&gt;string&lt;/code&gt;, which defines the text to be sent on the message. However, the message could be more complex and in this case &lt;a href="https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject" rel="noopener noreferrer"&gt;described with JSON schema&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can review and copy &lt;a href="https://gist.github.com/mikeyny/2ab889716486944ff1eba999b4108190" rel="noopener noreferrer"&gt;the full file here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Generate the Application Code with AsyncAPI Generator
&lt;/h3&gt;

&lt;p&gt;After creating your AsyncAPI file, you can use the AsyncAPI Generator to automatically generate the code for your event-driven application. The AsyncAPI Generator is a command-line tool that can &lt;a href="https://github.com/asyncapi/generator#list-of-official-generator-templates" rel="noopener noreferrer"&gt;generate code in multiple languages&lt;/a&gt;, including JavaScript, Python, and Go.&lt;/p&gt;

&lt;p&gt;To use the AsyncAPI Generator, you will first need to install it using npm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g @asyncapi/generator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have installed the AsyncAPI Generator, you can use it to generate the code for your event-driven application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The generated code is meant to be a starting point, not a comprehensive build-and-use solution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The following command generates a functional node application from your AsyncAPI file. Make sure to replace the file and server names where appropriate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ag asyncapi.yaml @asyncapi/nodejs-template -p server=testing  -o example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command tells the AsyncAPI generator to generate Node.js code using the &lt;code&gt;asyncapi.yaml&lt;/code&gt; file that you created in the previous step. The generator will generate the code for the testing server we have just defined with our AsyncAPI file, and output those new files to a folder named &lt;code&gt;example&lt;/code&gt;. The AsyncAPI Generator supports code generation in &lt;a href="https://github.com/asyncapi/generator#list-of-official-generator-templates" rel="noopener noreferrer"&gt;many different languages&lt;/a&gt; such as Node, Java, Python, and Go.&lt;/p&gt;

&lt;p&gt;After running the command, you should have a full-fledged node application powering your event-driven application.&lt;/p&gt;

&lt;p&gt;You can run the following to install the dependencies and run the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; node src/api/index.js

 SUB  Subscribed to chat
 PUB  Will eventually publish to chat
Chat Application 1.0.0 is ready!

🔗  MQTT adapter is connected!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Test the AsyncAPI Node.js Application
&lt;/h3&gt;

&lt;p&gt;To test the application, you need to send messages to the broker as a publisher. You can do this using the &lt;code&gt;MQTT.js&lt;/code&gt; library. Install it by running the following command in a separate terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;mqtt &lt;span class="nt"&gt;-g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the following command to send a message to the message broker. This command sends a publish command to the test broker on the &lt;code&gt;chat&lt;/code&gt; channel defined in your AsyncAPI file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mqtt pub &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s1"&gt;'chat'&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="s1"&gt;'test.mosquitto.org'&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Hello World"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running this command, check the original window running the chat application, and you should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;← chat was received:
&lt;span class="s1"&gt;'{text: Hello World}'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This output means your application successfully received your message from the message broker. If you want to start implementing business logic, you can review the code in the example directory.&lt;/p&gt;

&lt;p&gt;You will find the handler for the messages under &lt;code&gt;examples/src/api/handlers/chat.js&lt;/code&gt;. The file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * 
 * @param {object} options
 * @param {object} options.message
 */&lt;/span&gt;
&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessageReceieved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Implement your business logic here...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * 
 * @param {object} options
 * @param {object} options.message
 */&lt;/span&gt;
&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Implement your business logic here...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Bump.sh with AsyncAPI
&lt;/h2&gt;

&lt;p&gt;By creating your AsyncAPI file, you actually also created an API contract ! You can &lt;a href="https://bump.sh/blog/api-contracts-extended-introduction" rel="noopener noreferrer"&gt;read all about them here&lt;/a&gt; but in short, an API contract specifies the components and describes the behavior of an API, for instance available events and data or the rules for using the API.&lt;/p&gt;

&lt;p&gt;You saw this earlier with the chat application implementation; you had to define the different channels as well as the operations that a client could perform on each channel.&lt;/p&gt;

&lt;p&gt;Having a clear and formal API contract can ensure that the different components of an event-driven system can communicate and work together effectively. It can also make it easier to collaborate with other developers and teams, since everyone will have a clear understanding of the API and how it’s working.&lt;/p&gt;

&lt;p&gt;You can use Bump.sh to document and keep track of the changes in your event-driven API via its AsyncAPI API contract. &lt;/p&gt;

&lt;p&gt;To use Bump.sh and generate your AsyncAPI based documentation, simply &lt;a href="https://bump.sh/users/sign_up?utm_source=bump&amp;amp;utm_medium=blog&amp;amp;utm_campaign=asyncapi-example-blog" rel="noopener noreferrer"&gt;create an account&lt;/a&gt;. Then you can simply drag and drop your AsyncAPI file in the onboarding flow.&lt;/p&gt;

&lt;p&gt;After signing up, fill out the following form with the details of your API:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx03ohynzs6fgtxmd9awn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx03ohynzs6fgtxmd9awn.png" alt="Bump.sh onboarding screen" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can then proceed to upload your AsyncAPI file manually or using &lt;a href="https://github.com/bump-sh/cli" rel="noopener noreferrer"&gt;Bump.sh CLI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To upload your file using the CLI start by installing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; bump-cli &lt;span class="c"&gt;# using npm&lt;/span&gt;
yarn global add bump-cli &lt;span class="c"&gt;# using yarn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then preview your generated API documentation by running :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bump preview path/to/file.json/yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI will respond with an URL that, if visited, will let you visualize for a few minutes how your API documentation would render in Bump.sh.&lt;/p&gt;

&lt;p&gt;When your AsyncAPI file is ready to be deployed, you can follow the simple steps of the &lt;a href="https://docs.bump.sh/help/getting-started/" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt; to have your API documentation live and ready to share.&lt;/p&gt;

&lt;p&gt;You can also connect the Bump.sh CLI to CI/CD tools, and there is even a GitHub Action you can add to any project. Which will allow you to automatically track and inform about API changes and deploy new versions of your API, among other cool possibilities you can read about on the &lt;a href="https://github.com/marketplace/actions/bump-sh" rel="noopener noreferrer"&gt;Bump.sh page in GitHub marketplace&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Event-driven APIs lead to real-time, responsive, and loosely-coupled systems, and AsyncAPI is a great way to define those APIs. By using AsyncAPI and Bump.sh together, you can create high-quality documentation for all your event-driven APIs.&lt;/p&gt;

&lt;p&gt;Feel free to reach out to us if you have feedback, comments, or suggestions you’d like to share!&lt;/p&gt;

</description>
      <category>asyncapi</category>
      <category>eventdriven</category>
      <category>api</category>
      <category>node</category>
    </item>
    <item>
      <title>AsyncAPI vs. OpenAPI: Which Specification Is Right for Your App?</title>
      <dc:creator>Bump.sh</dc:creator>
      <pubDate>Thu, 03 Aug 2023 16:45:00 +0000</pubDate>
      <link>https://dev.to/bump/asyncapi-vs-openapi-which-specification-is-right-for-your-app-9l8</link>
      <guid>https://dev.to/bump/asyncapi-vs-openapi-which-specification-is-right-for-your-app-9l8</guid>
      <description>&lt;p&gt;Depending on how your application is designed and what it needs to accomplish, you probably want to consider choosing one type of communication protocol for your API over another—namely, synchronous or asynchronous. And which protocol you use determines which specification you need to follow for your API—&lt;a href="https://www.openapis.org/" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt; or &lt;a href="https://www.asyncapi.com/" rel="noopener noreferrer"&gt;AsyncAPI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s take a brief look at the differences between synchronous and asynchronous APIs, and then we’ll talk about whether OpenAPI or AsyncAPI is best for communicating the ins and outs of your API to your users. &lt;/p&gt;

&lt;h2&gt;
  
  
  Synchronous vs. Asynchronous APIs
&lt;/h2&gt;

&lt;p&gt;Synchronous and asynchronous APIs differ mainly in how they process information.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Synchronous&lt;/em&gt; APIs respond to each client request with only minimal elapsed time, and clients must wait for the response before code execution can continue. This is the type of API that supports most of the internet, and they typically use the &lt;a href="https://en.wikipedia.org/wiki/Representational_state_transfer" rel="noopener noreferrer"&gt;REST protocol&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Asynchronous&lt;/em&gt; APIs may provide a callback or notification when requested resources are ready, allowing clients to continue functioning without tying up resources waiting for a response from the API. These APIs use pub-sub messaging queues like &lt;a href="https://mqtt.org/" rel="noopener noreferrer"&gt;MQTT&lt;/a&gt; and &lt;a href="https://www.rabbitmq.com/" rel="noopener noreferrer"&gt;RabbitMQ&lt;/a&gt;, data streams like &lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;Kafka&lt;/a&gt;, or bidirectional communication protocols like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" rel="noopener noreferrer"&gt;WebSockets&lt;/a&gt;. IoT devices also commonly use asynchronous APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Between OpenAPI and AsyncAPI
&lt;/h2&gt;

&lt;p&gt;Documentation of your APIs is critical for communicating between backend and frontend developers. And good documentation can go beyond just improving the development experience - it can even increase adoption of your API.&lt;/p&gt;

&lt;p&gt;Industry-standard specifications like OpenAPI and AsyncAPI ensure that you’re effectively communicating to your users how they can interact with your API through an &lt;a href="https://bump.sh/blog/api-contracts-extended-introduction?utm_source=bump&amp;amp;utm_medium=blog&amp;amp;utm_campaign=blog-asyncapi-vs-openapi" rel="noopener noreferrer"&gt;API contract&lt;/a&gt;. Which spec you use to define and document your API depends on your use case, available resources, engineering team and community support, and chosen protocol to transmit data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In general, synchronous APIs can be defined using the OpenAPI standard, and asynchronous APIs can be defined using the AsyncAPI standard.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Protocols
&lt;/h3&gt;

&lt;p&gt;OpenAPI is typically used for RESTful APIs, which leverage HTTP or HTTPS as a transport protocol for data. The client makes a request to the server, which responds quickly (ideally within milliseconds or seconds). HTTP is mostly used as a unidirectional protocol, meaning the connection is closed after a single request and response. Each request must create a new connection to the server.&lt;/p&gt;

&lt;p&gt;To receive updates on any server changes, the client must rely on polling. Since the application does not know when a task will be completed, it must continue calling the API until the update is detected.&lt;/p&gt;

&lt;p&gt;AsyncAPI is based on event driven architectures (EDA). In this context, the sender and recipient don’t have to wait for a response from the other to do their next task or request.&lt;/p&gt;

&lt;p&gt;In event driven architectures, as you might have guess, it all revolves around events. An event is defined as a change of state. &lt;br&gt;
In an EDA, when an change of state occurs, the producer captures that event and sends it to all consumers who have subscribed to this event. There can be a broker in the middle in some cases. This way of architecturing APIs is refered to as Asynchronous.&lt;/p&gt;

&lt;p&gt;Asynchronous APIs can use bidirectional protocols, where a connection is maintained until it’s terminated by either the client or the server. Communication protocols like WebSockets allow the application to request data from the server but continue other processing while it waits for the response. Once resources are available to generate the response, the API produces a response, and the WebSocket connection streams the information back to the application.&lt;/p&gt;

&lt;p&gt;Applications can also subscribe to a channel on a message broker like MQTT, Kafka, or RabbitMQ where they can receive updates or notifications as events occur. When updates are no longer needed, the subscription can be terminated. &lt;/p&gt;

&lt;p&gt;A single API can make use of multiple protocols. We’ll talk more about that in a bit, but for now, suffice it to say that an API can combine synchronous and asynchronous methodologies, as well as use multiple asynchronous protocols. GraphQL APIs, for example, send queries over HTTP (a synchronous protocol), but also provide asynchronous messaging with WebSockets. &lt;/p&gt;

&lt;h3&gt;
  
  
  Simplicity of Implementation
&lt;/h3&gt;

&lt;p&gt;Since OpenAPI and AsyncAPI support different communication protocols, they require different skills to implement and different amounts of work as well. &lt;/p&gt;

&lt;p&gt;To implement an API designed according to OpenAPI, developers can use web application frameworks to set up the actual API. Authentication is also &lt;a href="https://spec.openapis.org/oas/latest.html#security-scheme-object" rel="noopener noreferrer"&gt;built into the standard&lt;/a&gt;, so everything needed to create your synchronous API is present once your OpenAPI document is created. Since synchronous APIs send messages directly to the endpoint, there’s no additional architecture required to build the API.&lt;/p&gt;

&lt;p&gt;On the other hand, implementing an asynchronous API is more complicated. Developers can still use web application frameworks, but they do need more architecture support than that. If your API uses a message broker as a middleman between application and API, that needs to be designed and built. If you’re using WebSockets to push notifications, both the server and the application need listener functions that keep the connection open.&lt;/p&gt;

&lt;h3&gt;
  
  
  Community Support
&lt;/h3&gt;

&lt;p&gt;AsyncAPI and OpenAPI are both open-source standards and part of the &lt;a href="https://www.linuxfoundation.org/" rel="noopener noreferrer"&gt;Linux Foundation&lt;/a&gt;. Both are stable, well-maintained specifications and should be supported well into the future. Still, there are a handful of differences when it comes to their ecosystems.&lt;/p&gt;

&lt;p&gt;OpenAPI is a more established standard, since it was developed for synchronous REST APIs. The OpenAPI specification has many contributors from the Linux Foundation and the community. Many more have contributed to the standard through discussion and examples. The &lt;a href="https://www.openapis.org/participate/how-to-contribute/governance" rel="noopener noreferrer"&gt;governance model of the OpenAPI Initiative&lt;/a&gt; allows both community and industry contributions in an effort to keep the specification vendor-neutral. To contribute, you must meet requirements for &lt;a href="https://www.openapis.org/membership/join" rel="noopener noreferrer"&gt;membership in the initiative&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;AsyncAPI is a newer standard based on OpenAPI. While it has fewer code contributors than OpenAPI, its popularity is quickly growing. AsyncAPI &lt;a href="https://www.asyncapi.com/blog/2021-summary" rel="noopener noreferrer"&gt;attributes its rising success&lt;/a&gt; to its community support and all the hosted tools related to AsyncAPI. In late 2020, AsyncAPI also formed an open governance model to &lt;a href="https://www.asyncapi.com/blog/governance-motivation" rel="noopener noreferrer"&gt;assure the community&lt;/a&gt; that no single company has control over AsyncAPI and that this initiative is, in fact, community driven. They even are &lt;a href="https://www.asyncapi.com/blog/asyncapi-joins-linux-foundation" rel="noopener noreferrer"&gt;a Linux Foundation Project&lt;/a&gt; since 2021.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Cases
&lt;/h3&gt;

&lt;p&gt;Now, as we’ve already mentioned, whether you would use OpenAPI or AsyncAPI specification depends on what protocols your API uses. Which protocol you use depends on your specific use case and what backend resources are available for support. In general, OpenAPI is used to define APIs that provide immediate feedback (synchronous). The AsyncAPI spec defines APIs that don’t need to respond immediately to a request (asynchronous).&lt;/p&gt;

&lt;p&gt;But let’s see how that works out in some everyday use cases. When does one implementation have an advantage over the other?&lt;/p&gt;

&lt;h4&gt;
  
  
  RESTful APIs
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Representational_state_transfer" rel="noopener noreferrer"&gt;REST&lt;/a&gt; is a software architecture style commonly used to support APIs used on the web, and as mentioned earlier, synchronous APIs carry the day here. These are simple, uniform interfaces that are often used to support cloud applications and cloud services because they’re stateless, consistently available, and widely accessible. With these traits, a RESTful API can provide information on virtually any topic easily and reliably.&lt;/p&gt;

&lt;h4&gt;
  
  
  Internet of Things
&lt;/h4&gt;

&lt;p&gt;Internet of Things (IoT) devices need to handle inconsistent communications between the device and the API. For example, an IoT device may go out of internet range periodically, but will still need to send data to the API for processing. This means that data may be sent in bursts to the API when a connection is available. IoT devices may also need to notify the API when a significant event has occurred, as when a smoke alarm goes off or a camera detects motion. &lt;/p&gt;

&lt;p&gt;As a result of event processing, an IoT device may need to receive asynchronous notifications from the server. While the device itself holds raw data, servers collect and perform calculations of the data over time. The server may need to send notifications to the device when an event has occurred, like an IoT device losing power in your home.&lt;/p&gt;

&lt;h4&gt;
  
  
  Combining Synchronous and Asynchronous APIs
&lt;/h4&gt;

&lt;p&gt;Many SaaS API offerings exist to set up shopping carts for users and store inventory management for owners. These solutions tend to include a mixture of synchronous and asynchronous APIs. &lt;/p&gt;

&lt;p&gt;Inventory management applications, for example, use asynchronous API resources that allow users and owners to retrieve information about available inventory, user accounts, and pricing. Business owners can update their inventory, and it's automatically available to users when the API pushes data to the message broker. However, remember that synchronous APIs support most of the internet. An online retail shop may very well want the reliability of a RESTful API as part of its system to facilitate communication with a wide array of other organizations and developers.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Documenting in Any Case
&lt;/h2&gt;

&lt;p&gt;Regardless of which specification you choose to develop your API with, users need to be aware of new features and changes. Maintaining your API’s documentation and ensuring that it keeps to the standards of your spec can be a time-hungry task.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bump.sh/?utm_source=bump&amp;amp;utm_medium=blog&amp;amp;utm_campaign=blog-asyncapi-vs-openapi" rel="noopener noreferrer"&gt;Bump.sh&lt;/a&gt; transforms your OpenAPI and AsyncAPI documents into beautiful documentation. It lets your developers focus on building products rather than maintaining docs. Bump.sh provides automatic change detection by integrating with &lt;a href="https://docs.bump.sh/help/continuous-integration?utm_source=bump&amp;amp;utm_medium=blog&amp;amp;utm_campaign=blog-asyncapi-vs-openapi" rel="noopener noreferrer"&gt;CI tools&lt;/a&gt;, pushing notifications of the change to stakeholders, and enabling validation via its simple-to-use interface. &lt;a href="https://bump.sh/users/sign_up?utm_source=bump&amp;amp;utm_medium=blog&amp;amp;utm_campaign=blog-asyncapi-vs-openapi" rel="noopener noreferrer"&gt;Take its free trial for a spin&lt;/a&gt; to see how Bump.sh can make documenting any API - OpenAPI or AsyncAPI - simple. You can also try any AsyncAPI or OpenAPI file in the preview at the bottom of this page.&lt;/p&gt;

&lt;h2&gt;
  
  
  So… Which one to pick?
&lt;/h2&gt;

&lt;p&gt;To summarize, &lt;strong&gt;the API specification you should use depends entirely on what type of API you want to build&lt;/strong&gt;. Long story short, synchronous APIs use simple, direct endpoint communication to link a client to a server. When data consists of simple requests that can be completed by the server quickly, a synchronous, RESTful API that follows the OpenAPI specification is what you want.&lt;/p&gt;

&lt;p&gt;Asynchronous APIs use message brokers or pub-sub to communicate between server and application as data is made available. They’re useful for real-time applications that require frequent updates. They can be more complex to implement since they require more architecture than synchronous APIs, but you can stay organized thanks to the AsyncAPI specification.&lt;/p&gt;

&lt;p&gt;Both OpenAPI and AsyncAPI are open-source specifications and provide a standard method for designing and implementing APIs. A key asset of both specs is the ability to create comprehensive, industry-standard documentation for your API. By connecting your documents to &lt;a href="https://bump.sh/?utm_source=bump&amp;amp;utm_medium=blog&amp;amp;utm_campaign=blog-asyncapi-vs-openapi" rel="noopener noreferrer"&gt;Bump.sh&lt;/a&gt;, you can rest assured that your documentation is automatically updated for each API release.&lt;/p&gt;

&lt;p&gt;Author: Joanna Wallace&lt;/p&gt;

</description>
      <category>express</category>
      <category>openapi</category>
      <category>api</category>
      <category>restapi</category>
    </item>
    <item>
      <title>Creating an API with Express.js using OpenAPI</title>
      <dc:creator>Bump.sh</dc:creator>
      <pubDate>Mon, 24 Jul 2023 12:06:00 +0000</pubDate>
      <link>https://dev.to/bump/creating-an-api-with-expressjs-using-openapi-2749</link>
      <guid>https://dev.to/bump/creating-an-api-with-expressjs-using-openapi-2749</guid>
      <description>&lt;p&gt;&lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt; is a popular backend JavaScript framework for building landing pages and integrated content management systems or integrating APIs with other tools. With over &lt;a href="https://www.npmjs.com/package/express" rel="noopener noreferrer"&gt;twenty million weekly downloads on npm&lt;/a&gt; at the time of writing, the framework's popularity comes from its ease of setup and use, extensibility with first- and third-party middleware functions, and its flexible built-in router.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.openapis.org/" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt; is a standard for describing HTTP APIs in a document that humans and computers alike can understand or consume. Building APIs according to the OpenAPI specification can ease friction between an API's developer and its consumers, especially in terms of how the API should operate. Some knowledge about the OpenAPI specification can definitely help you understand the examples provided.&lt;/p&gt;

&lt;p&gt;In this article, you'll learn how to build REST APIs using Express. You'll also learn how to document your APIs according to the OpenAPI specification with &lt;code&gt;express-openapi&lt;/code&gt;. Finally, you'll learn how to effectively manage your API documentation using &lt;a href="https://bump.sh/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=express-openapi-blog" rel="noopener noreferrer"&gt;Bump.sh&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crash Course in Express
&lt;/h2&gt;

&lt;p&gt;The Express architecture is based around &lt;a href="https://expressjs.com/en/guide/using-middleware.html" rel="noopener noreferrer"&gt;middleware&lt;/a&gt;, which are functions that can access and modify the request and response object and either return a response or trigger subsequent middleware functions. Middleware can be registered by invoking the &lt;code&gt;.use()&lt;/code&gt; method on an Express application, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;middlewareFunction&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-middleware-function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;middlewareFunction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Express has three &lt;a href="https://expressjs.com/en/guide/using-middleware.html#middleware.built-in" rel="noopener noreferrer"&gt;built-in middleware functions&lt;/a&gt; for serving static files (&lt;code&gt;express.static&lt;/code&gt;, parsing JSON (&lt;code&gt;express.json&lt;/code&gt;) and URL-encoded request payloads (&lt;code&gt;express.urlencoded&lt;/code&gt;). Together with the Express router, these provide a good starting point for most applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Case for OpenAPI
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://bump.sh/blog/what-is-openapi?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=express-openapi-blog" rel="noopener noreferrer"&gt;OpenAPI specification&lt;/a&gt; is an opinionated, language-agnostic standard for describing HTTP APIs that allows humans and machines to understand and interact with an API without the need to access the source code. A valid OpenAPI description document is also called an &lt;a href="https://bump.sh/blog/api-contracts-extended-introduction?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=express-openapi-blog" rel="noopener noreferrer"&gt;API contract&lt;/a&gt; because, like a contract, it enforces a specific behavior that must be implemented by the developer and adhered to by the consumer.&lt;/p&gt;

&lt;p&gt;An API contract adds value in many ways, including easing the development burden, improving ease of adoption for first-time consumers, and using automated tools to reduce the amount of work needed to generate client code and documentation or validate I/O data.&lt;/p&gt;

&lt;p&gt;In the next few sections, we'll see API contracts in action as we build an Express application and generate documentation with Bump.sh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing an API with OpenAPI and Express
&lt;/h2&gt;

&lt;p&gt;In this section, using Express, you'll build an API that follows the OpenAPI specification. You will be walked through steps to set up an Express application, configure it according to the OpenAPI spec, and see how to view your API documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;In order to follow along with this tutorial, you'll need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Familiarity with JavaScript (and Node.js)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A Node.js package manager — &lt;code&gt;npm&lt;/code&gt; was used in this article&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://bump.sh/users/sign_up/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=express-openapi-blog" rel="noopener noreferrer"&gt;Bump.sh account&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the source code for the project in &lt;a href="https://github.com/bump-sh/express-oas-api-example/tree/main" rel="noopener noreferrer"&gt;this GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating an Express Application
&lt;/h3&gt;

&lt;p&gt;Let's start with creating an Express application. As mentioned, one of the reasons Express is so popular is that it's quick and easy to set up.&lt;/p&gt;

&lt;p&gt;First, create a new folder for your project. Spin up a terminal session and run the following command to create a folder named &lt;code&gt;express-oas&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;express-oas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, initialize a JavaScript project by adding a &lt;strong&gt;package.json&lt;/strong&gt; file. Using the same terminal session or via your computer's file manager, create a file named &lt;strong&gt;package.json&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;express-oas
&lt;span class="nb"&gt;touch &lt;/span&gt;package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the &lt;strong&gt;package.json&lt;/strong&gt; file using a text editor, then copy and paste the following in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"express-oas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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 class="nl"&gt;"dependencies"&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 class="nl"&gt;"express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.18.2"&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 class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use &lt;code&gt;npm init&lt;/code&gt; or &lt;code&gt;yarn init&lt;/code&gt; to automatically generate a &lt;strong&gt;package.json&lt;/strong&gt; file. Both &lt;code&gt;npm init&lt;/code&gt; and &lt;code&gt;yarn init&lt;/code&gt; (on Yarn Classic) run interactively, meaning that you'll need to respond to a series of prompts before the file is generated. To skip these prompts and use the defaults, you can run the command with the &lt;code&gt;-y&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run interactively&lt;/span&gt;
npm init

&lt;span class="c"&gt;# Run non-interactively&lt;/span&gt;
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, install the &lt;code&gt;express&lt;/code&gt; package dependency from the npm or yarn registry and create your Express application.&lt;/p&gt;

&lt;p&gt;In your terminal, run the command to install dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a file named &lt;strong&gt;index.js&lt;/strong&gt; in your project's root folder. You can do that via the terminal by running the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open this file using your text editor, then import and initialize your Express application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server running on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default export from the &lt;code&gt;express&lt;/code&gt; package is a function that, when invoked, creates an &lt;code&gt;express&lt;/code&gt; application instance. This instance or object contains methods for routing HTTP requests, configuring middleware, and binding and listening for connections on a specified host and port.&lt;/p&gt;

&lt;p&gt;In the code block above, you configured an Express application and registered the &lt;code&gt;json()&lt;/code&gt; middleware, which parses incoming requests with JSON payloads and a matching &lt;code&gt;Content-Type&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;If you try to access the application at this stage by running &lt;code&gt;node index.js&lt;/code&gt; and navigating to &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; on a web browser, you'll be greeted by an error. There's no need to worry about this, however, as it just indicates that there are no routes or logic configured in your application yet. In the next section, we'll add some logic and set up the application's documentation with &lt;code&gt;express-openapi&lt;/code&gt;, an OpenAPI framework for Express.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrating OpenAPI with express-openapi
&lt;/h3&gt;

&lt;p&gt;For developing APIs, it helps to think of the API as a collection of resources, with each resource represented by a simple object that can be—from the moment of its creation—viewed, modified, or destroyed.&lt;/p&gt;

&lt;p&gt;For simplicity, you can use this &lt;a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete#RESTful_APIs" rel="noopener noreferrer"&gt;create, read, update, and delete (CRUD)&lt;/a&gt; pattern to help plan or design your API quickly. You can set up an OpenAPI-compliant API in a few steps using the &lt;code&gt;express-openapi&lt;/code&gt; package. For this one we will assume that our project has only one resource, called &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;express-openapi&lt;/code&gt; is an un-opinionated OpenAPI framework for Express, which supports OpenAPI versions 2.x and 3.0 at the time of writing. Configuration can be done in JavaScript or from a YAML string/file. In this project, you'll be using a JavaScript object.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;express-openapi&lt;/code&gt; allows you to keep the OpenAPI definition in sync with the code. Basically, you will provide an OpenAPI definition file with empty paths and they will be populated from your code. Doing this ensures the OpenAPI file will be exactly reflecting how the code behaves, updated as the code is. It also allows you if you go play around with the tool to validate your schemas, automatically provide &lt;code&gt;res.validateResponse&lt;/code&gt; tailored to a particular route, helps with your API security management, and so much more I can’t list them all now. The whole purpose of this framework is to stay as close as possible to express while leveraging the power of OpenAPI.&lt;/p&gt;

&lt;p&gt;To get started, run this command in your terminal to install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;express-openapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the &lt;strong&gt;index.js&lt;/strong&gt; file in your editor and add the following import near the top of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; initialize &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'express-openapi'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;initialize&lt;/code&gt; import is a function that accepts a configuration object and sets up an OpenAPI-compliant contract that can be viewed or generated for your API. The required configuration parameters are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a reference to an Express application&lt;/li&gt;
&lt;li&gt;an &lt;code&gt;operations&lt;/code&gt; object containing exposed HTTP methods and handler functions&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;paths&lt;/code&gt; string that points to a directory where route files can be found&lt;/li&gt;
&lt;li&gt;an &lt;code&gt;apiDoc&lt;/code&gt; object describing the API's base definition, including schemas of objects used in your documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that either &lt;code&gt;operations&lt;/code&gt; or &lt;code&gt;paths&lt;/code&gt; will be required at any time. This means that if &lt;code&gt;operations&lt;/code&gt; is present, then &lt;code&gt;paths&lt;/code&gt; isn't required and vice versa.&lt;/p&gt;

&lt;p&gt;Now make the following changes to the &lt;strong&gt;index.js&lt;/strong&gt; file to see what this config looks like in action.&lt;/p&gt;

&lt;p&gt;As first argument, you need to pass a reference to your Express app, then optionally specify a path to the &lt;code&gt;docsPath&lt;/code&gt; keyword if you want the API contract file to be served by your server, in development mode this can be useful (as you will see later when using the Bump.sh CLI), however in production mode you might want to remove this and replace it with the &lt;code&gt;exposeApiDocs: false&lt;/code&gt; option. Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;docsPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api-definition&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;exposeApiDocs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NODE_ENV&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, configure the &lt;code&gt;apiDoc&lt;/code&gt; object by specifying the path of a file containing the base of your API definition. In this tutorial, you'll be using OpenAPI 3.1. Add the &lt;code&gt;apiDoc&lt;/code&gt; file path to the &lt;code&gt;initialize&lt;/code&gt; config object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// other objects here..&lt;/span&gt;
  &lt;span class="na"&gt;apiDoc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./doc/api-definition-base.yml&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And create the file &lt;code&gt;./doc/api-definition-base.yml&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;openapi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.1.0"&lt;/span&gt;
&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;getting&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;started&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;API"&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0.0"&lt;/span&gt;
&lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/"&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;User&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object"&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string"&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user's&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;unique&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;identifier"&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string"&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user's&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;preferred&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;name"&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string"&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;address"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the API definition &lt;strong&gt;paths&lt;/strong&gt; property is an empty object. This is because &lt;code&gt;express-openapi&lt;/code&gt; will generate its members based on the value of the &lt;code&gt;paths&lt;/code&gt; property given in the &lt;code&gt;initialize&lt;/code&gt; function dynamically, which you'll add next.&lt;/p&gt;

&lt;p&gt;To do this, we will import javascript files by adding the folder path or our API endpoints logic to the &lt;code&gt;initialize&lt;/code&gt; function call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="c1"&gt;// rest of code omitted for clarity&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./paths&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you'll need to add a route with some operations to complete the &lt;code&gt;express-openapi&lt;/code&gt; initialization. The &lt;code&gt;express-openapi&lt;/code&gt; package uses filesystem-based routing. Let's look at the following routes we want to define:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /users
PUT /users/:id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They would need the following files to be created (assuming &lt;code&gt;./&lt;/code&gt; is the starting directory):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./paths/users.js
./paths/users/{id}.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While we'll be using more routes, these two files will be enough for what our project needs, so go ahead and create them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; paths/users
&lt;span class="nb"&gt;cd &lt;/span&gt;paths
&lt;span class="nb"&gt;touch &lt;/span&gt;users.js
&lt;span class="nb"&gt;cd users
touch&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll add some logic to our API application inside these files. Each file will contain a function as its default export, and this function will act as the corresponding path handler. For example, requests sent to &lt;code&gt;/users&lt;/code&gt; will be handled by the function exported in &lt;code&gt;./paths/users.js&lt;/code&gt;, and requests sent to &lt;code&gt;/users/{uniqueId}&lt;/code&gt; will be handled by the function exported in &lt;code&gt;./paths/users/{id}.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, open the &lt;strong&gt;users.js&lt;/strong&gt; file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;operations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;operations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add the following code to the &lt;strong&gt;users/{id}.js&lt;/strong&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;operations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;PUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;DELETE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PUT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DELETE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="nx"&gt;PUT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="nx"&gt;DELETE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;operations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's quickly break down what's happening in these files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have a function as the default export, and this function returns an object representing valid operations (HTTP methods) for the route.&lt;/li&gt;
&lt;li&gt;As mentioned earlier, the file names correspond to the route that will be matched when your API is queried.&lt;/li&gt;
&lt;li&gt;For each operation defined in the &lt;code&gt;operations&lt;/code&gt; object, you need a corresponding handler function, and the function name must match the HTTP verb (PUT, GET, etc).&lt;/li&gt;
&lt;li&gt;Finally, the documentation for each handler function can be described by adding an &lt;code&gt;apiDoc&lt;/code&gt; property to the handler functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What's missing now are: your API documentation and the actual API logic. We'll add those in the next few steps.&lt;/p&gt;

&lt;p&gt;First let's add your API endpoints documentation. We will update the &lt;code&gt;apiDoc&lt;/code&gt; property for the GET and POST handler functions in the &lt;strong&gt;users.js&lt;/strong&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./paths/users.js&lt;/span&gt;
&lt;span class="c1"&gt;// rest of code hidden for clarity&lt;/span&gt;

&lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Returns list of users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getUsers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;List of users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#/components/schemas/User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Creates a new user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;createUser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#/components/schemas/User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Newly created user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#/components/schemas/User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// rest of code hidden for clarity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll also add the documentation for the GET, PUT, and DELETE handler functions in the &lt;strong&gt;users/{id}.js&lt;/strong&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./paths/users/{id}.js&lt;/span&gt;
&lt;span class="c1"&gt;// rest of code hidden for clarity&lt;/span&gt;

&lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Returns a single user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getOneUser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#/components/schemas/User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;PUT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Updates an existing user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;updateUser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#/components/schemas/User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Updated user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#/components/schemas/User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;DELETE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Deletes an existing user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deleteUser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;apiDoc&lt;/code&gt; property of a function handler defines the OpenAPI documentation for that endpoint while the summary and operationId fields provide a brief description and a unique identifier, respectively. &lt;a href="https://expressjs.com/en/guide/routing.html#route-parameters" rel="noopener noreferrer"&gt;Route parameters&lt;/a&gt; and the required format for the request body data can be configured with the &lt;code&gt;parameters&lt;/code&gt; and &lt;code&gt;requestBody&lt;/code&gt; fields, respectively. Finally, the &lt;code&gt;responses&lt;/code&gt; field provides information about the possible responses—and their status codes—for an endpoint.&lt;/p&gt;

&lt;p&gt;Next, update the function handlers to include CRUD logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./paths/users.js&lt;/span&gt;

&lt;span class="c1"&gt;// rest of code hidden for clarity&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockDatabaseInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;mockDatabaseInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockDatabaseInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The GET and POST function handlers here respond to GET and POST requests made to &lt;code&gt;/users&lt;/code&gt;, respectively. The GET function retrieves all user data from a database, the &lt;code&gt;mockDatabaseInstance&lt;/code&gt;—which we'll get to later—and returns it in JSON format with a status code of 200. The POST function adds a new user to the database from data provided via the request's body and returns the updated user list with a status code of 201.&lt;/p&gt;

&lt;p&gt;We'll also need to update the function handlers in the &lt;strong&gt;/users/{id}.js&lt;/strong&gt; file. Open the file and update the GET, PUT, and DELETE functions to include the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./paths/users/{id}.js&lt;/span&gt;
&lt;span class="c1"&gt;// rest of code hidden for clarity&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mockDatabaseInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PUT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mockDatabaseInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DELETE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;mockDatabaseInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned earlier, requests made to &lt;code&gt;/users/someUniqueId&lt;/code&gt; will be routed to this file and handled according to their HTTP verbs. The GET function here retrieves a single user from the database, matching the ID provided in the request's path. The PUT function updates a single user, also matching the provided ID, and returns the updated user as JSON with a status code of 200. The DELETE function removes a user from the database using the ID provided in the request. No data is returned from the DELETE function, so the status code is 204.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;mockDatabaseInstance&lt;/code&gt; object referenced in the function handlers code is a simple object with methods for updating and reading from an in-memory data store (an array of objects). We can add this to our project by creating a file named &lt;strong&gt;database.js&lt;/strong&gt; in the project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;database.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And adding the following code to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mockDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;userExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;userExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// user already exists, let's throw an error&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User already exists.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;userExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// user does not exist, let's throw an error&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`No user with ID &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; was found`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updatedUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;updatedUser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;userExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// user does not exist, let's throw an error&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`No user with ID &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; was found`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;userExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// user does not exist, let's throw an error&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`No user with ID &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; was found`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;addUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;getOne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockDatabaseInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mockDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;mockDatabaseInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above defines a function named &lt;code&gt;mockDatabase&lt;/code&gt; that returns an object with multiple functions to perform CRUD operations on an in-memory data store, the &lt;code&gt;dataStore&lt;/code&gt; array. The functions &lt;code&gt;addUser&lt;/code&gt;, &lt;code&gt;updateUser&lt;/code&gt;, and &lt;code&gt;deleteUser&lt;/code&gt; respectively perform operations to add, update, or delete users from the data store. The &lt;code&gt;getOne&lt;/code&gt; and &lt;code&gt;getAll&lt;/code&gt; functions retrieve one or multiple users from the data store, while &lt;code&gt;userExists&lt;/code&gt; is a utility function for checking if a user with a matching ID exists in the data store.&lt;/p&gt;

&lt;p&gt;We instantiate and store the &lt;code&gt;mockDatabase&lt;/code&gt; in the &lt;code&gt;mockDatabaseInstance&lt;/code&gt; variable, and we export and use this in our function handlers. Let's update the rest of our code to include the &lt;code&gt;mockDatabaseInstance&lt;/code&gt; import.&lt;/p&gt;

&lt;p&gt;Open the files in your &lt;code&gt;paths&lt;/code&gt; directory, and add the following line at the top of each file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mockDatabaseInstance&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../database.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that for the &lt;strong&gt;paths/users/{id}.js&lt;/strong&gt; file, you need to add two dots and a slash (../) as it's nested one level deep:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mockDatabaseInstance&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../database.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, your API and its contract have been set up. When you test your application in the next section, you'll see that errors will be thrown for invalid requests or payloads that don't conform to the documentation you've described. This is where the &lt;code&gt;express-openapi&lt;/code&gt; library shines as you didn't need to define any validation code but the provided documentation schemas and constraints will do all the job for you.&lt;/p&gt;

&lt;p&gt;While you've learned to create an Express application with &lt;code&gt;express-openapi&lt;/code&gt; in this section, it's been light on information about the OpenAPI specification and the &lt;code&gt;express-openapi&lt;/code&gt; package. You can start with the &lt;a href="https://learn.openapis.org/" rel="noopener noreferrer"&gt;OpenAPI guide&lt;/a&gt; if you'd like to learn more about the OpenAPI specification and the &lt;a href="https://github.com/kogosoftwarellc/open-api/tree/master/packages/express-openapi" rel="noopener noreferrer"&gt;express-openapi documentation&lt;/a&gt; for more information on how to use the package.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running and Testing the Application
&lt;/h3&gt;

&lt;p&gt;It's time to run and test the application. Simply run &lt;code&gt;node index.js&lt;/code&gt; and navigate to &lt;a href="http://localhost:3000/api-definition" rel="noopener noreferrer"&gt;http://localhost:3000/api-definition&lt;/a&gt; in a browser to see your API definition.&lt;/p&gt;

&lt;p&gt;You can also test the API by visiting &lt;a href="http://localhost:3000/users" rel="noopener noreferrer"&gt;http://localhost:3000/users&lt;/a&gt; to list the users in your database.&lt;/p&gt;

&lt;p&gt;In a production environment, you will probably want to deploy the updated API definition each time you make a change in your code without having to expose the API definition on your express server.&lt;/p&gt;

&lt;p&gt;To do so, copy the following script into a new file named &lt;code&gt;contract.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAPIFramework&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openapi-framework&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Use OpenAPIFramework similarly than in the express-openapi library&lt;/span&gt;
&lt;span class="c1"&gt;// to generate the OpenAPI definition file of our API&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;framework&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;OpenAPIFramework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;featureType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;middleware&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express-openapi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiDoc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./doc/api-definition-base.yml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./paths&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;

&lt;span class="c1"&gt;// Output OpenAPI definition&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiDoc&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simple script which uses the &lt;code&gt;express-openapi&lt;/code&gt; package to generate the API definition file without the need to run an Express server.&lt;/p&gt;

&lt;p&gt;So if you run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node contract.js &amp;gt; doc/api-definition.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be able to snapshot the current OpenAPI definition file inside the &lt;code&gt;doc/api-definition.json&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Bump.sh for Documenting Your Express APIs
&lt;/h2&gt;

&lt;p&gt;Using OpenAPI (and the &lt;code&gt;express-openapi&lt;/code&gt; package) enables you to use API contracts that make collaboration easy among developers when building and integrating with APIs. However, manually generating and maintaining these contracts can be tough, as you just saw. Bump.sh can improve this collaboration by helping documenting your API based on the contract.&lt;/p&gt;

&lt;p&gt;As an API documentation management solution, &lt;a href="https://bump.sh/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=express-openapi-blog" rel="noopener noreferrer"&gt;Bump.sh&lt;/a&gt; helps publish API contracts into developer portals, track changes, and alert teams when breaking changes are introduced. It essentially eases the workload of manually updating your API's documentation, communicating changes made to your API's consumers, and keeping track of all your product documentation.&lt;/p&gt;

&lt;p&gt;Bump.sh provides a &lt;a href="https://github.com/bump-sh/cli" rel="noopener noreferrer"&gt;command line interface (CLI) tool&lt;/a&gt; that lets you easily preview your API documentation while it's in development (with support for live reloading), deploy versions of your documentation automatically from your CI build step, compare changes made between versions of your API, as well as notify consumers of changes made to your APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure Bump.sh for Express Applications
&lt;/h3&gt;

&lt;p&gt;To configure Bump.sh for your Express app, you need to add the Bump.sh CLI to your existing Express project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;bump-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned, &lt;code&gt;bump-cli&lt;/code&gt; can be used to preview, compare versions, or deploy new versions of your API documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bump.sh/users/sign_up?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=express-openapi-blog" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; or &lt;a href="https://bump.sh/users/sign_in?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=express-openapi-blog" rel="noopener noreferrer"&gt;login&lt;/a&gt; in your Bump.sh  account. You can begin by navigating to your dashboard and clicking &lt;strong&gt;Create Documentation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvdwh5seq2d0dtpvi4ma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvdwh5seq2d0dtpvi4ma.png" alt="Bump.sh account dashboard" width="800" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, add your documentation's name and, optionally, specify its access level (public or private).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8onitchsjsxmi7soci6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8onitchsjsxmi7soci6.png" alt="Create new documentation wizard" width="800" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, you'll be asked to upload a specification file. Choose the &lt;strong&gt;Use Bump.sh CLI&lt;/strong&gt; option, which will immediately take you to the newly created documentation's deployment configuration page. Here, you'll find the token that's required to deploy your documentation using the CLI. It's the string labeled &lt;strong&gt;Access token&lt;/strong&gt;, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2kkf3w0jnuyxph7ku0ra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2kkf3w0jnuyxph7ku0ra.png" alt="Bump.sh deployment configuration" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy this token and replace &lt;code&gt;YOUR_TOKEN&lt;/code&gt; with it when running the command to deploy your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx bump deploy http://localhost:3000/api-definition &lt;span class="nt"&gt;--doc&lt;/span&gt; YOUR_DOCUMENTATION_SLUG &lt;span class="nt"&gt;--token&lt;/span&gt; YOUR_TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the command above will trigger a deployment that you can view by clicking &lt;strong&gt;View Documentation&lt;/strong&gt; from your documentation's General Settings page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frj4jn3ohyhq5w50eglnf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frj4jn3ohyhq5w50eglnf.png" alt="Documentation general settings" width="800" height="46"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your deployed documentation should open in a new tab, and it should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3em8ky42o0c8xizorhn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3em8ky42o0c8xizorhn.png" alt="Bump.sh deployed documentation" width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Automate API documentation update with Bump.sh
&lt;/h3&gt;

&lt;p&gt;In order to automatically deploy a new version of your documentation every time you push code changes to a branch, we will add the &lt;a href="https://docs.bump.sh/help/continuous-integration/github-actions/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=express-openapi-blog" rel="noopener noreferrer"&gt;Bump.sh Github Action&lt;/a&gt; to your repository.&lt;/p&gt;

&lt;p&gt;To deploy a new version on each push, create a file named &lt;code&gt;bump-deploy.yml&lt;/code&gt; in the &lt;code&gt;.github/workflows&lt;/code&gt; folder of your project, then paste the following code into the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy documentation&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy-doc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy API doc on Bump.sh&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install NodeJS&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install node dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate OpenAPI contract&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node contract.js &amp;gt; doc/api-definition.json&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy API documentation&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bump-sh/github-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;doc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;BUMP_DOC_ID&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{secrets.BUMP_TOKEN}}&lt;/span&gt;
          &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;doc/api-definition.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow runs every time &lt;code&gt;git push&lt;/code&gt; is run on the &lt;code&gt;main&lt;/code&gt; branch. It will generate the API definition thanks to the &lt;code&gt;contract.js&lt;/code&gt; script, then deploy the API definition file to Bump.sh thanks to the Bump.sh Github Action.&lt;/p&gt;

&lt;p&gt;Just make sure you provide your Bump.sh documentation slug (replace the &lt;code&gt;&amp;lt;BUMP_DOC_ID&amp;gt;&lt;/code&gt; value) and an &lt;a href="https://docs.github.com/en/actions/security-guides/encrypted-secrets" rel="noopener noreferrer"&gt;encrypted secret&lt;/a&gt; containing the Bump.sh access token used earlier in a &lt;code&gt;BUMP_TOKEN&lt;/code&gt; secret variable on your repository.&lt;/p&gt;

&lt;p&gt;The resulting action should run on each push to the &lt;code&gt;main&lt;/code&gt; branch:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdytajfrhwwjmc28qrea.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdytajfrhwwjmc28qrea.png" alt="Github Action Deploy Summary" width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your API consumers can then subscribe to changes made to your API by clicking on &lt;strong&gt;API Changelog&lt;/strong&gt; from your API documentation page. Either by completing the form or adding the RSS feed link to apps that can display RSS feeds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9rfal8gjorcdfjluigg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9rfal8gjorcdfjluigg.png" alt="Subscribe to API changelog" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By following this tutorial, you created an Express application and documented the API according to the OpenAPI specification with the &lt;code&gt;express-openapi&lt;/code&gt; npm package. You also learnt how to deploy a live version of your API documentation using Bump.sh.&lt;/p&gt;

&lt;p&gt;Documenting your APIs correctly is key to your API quality, usability, maintainability and helps your API consumers quickly get up to speed with using your product, reducing the number of support tickets and issues related to consuming your API.&lt;/p&gt;

&lt;p&gt;Bump.sh helps with documenting your APIs but goes one step further by giving you tools like &lt;a href="https://bump.sh/api-change-management/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=express-openapi-blog" rel="noopener noreferrer"&gt;an automatic API changelog&lt;/a&gt; with notifications and diffs and a hub to manage all your API documentation in one place.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Author: &lt;a href="https://portal.draft.dev/writers/rec98fcDmrzNUcuZz" rel="noopener noreferrer"&gt;Jerry Ejonavi&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>express</category>
      <category>openapi</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A Developer's Guide to API-First Design</title>
      <dc:creator>Bump.sh</dc:creator>
      <pubDate>Wed, 14 Jun 2023 12:30:00 +0000</pubDate>
      <link>https://dev.to/bump/a-developers-guide-to-api-first-design-41f8</link>
      <guid>https://dev.to/bump/a-developers-guide-to-api-first-design-41f8</guid>
      <description>&lt;p&gt;API-first design is a software development approach built around the idea that the application programming interfaces (APIs) should be the primary focus of the development process, with other system components, such as the user interface (UI) being developed later.&lt;/p&gt;

&lt;p&gt;API-first design is becoming increasingly important as more and more organizations are turning to microservices and other architectural patterns to improve their ability to scale, innovate, and adapt to changing business needs. This approach enables the development of flexible and modular systems that can be easily integrated with diverse systems and services.&lt;/p&gt;

&lt;p&gt;In this article, you'll learn about the principles of API-first design and how it can benefit your organization. You'll understand how API-first design works and learn about the different stages of the API design process. By the end of this article, you'll have a comprehensive understanding of the benefits of API-first design, and how &lt;a href="https://bump.sh/?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-first-design" rel="noopener noreferrer"&gt;Bump.sh&lt;/a&gt; can serve as the single source of truth for all your APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Is API-first Design Important?
&lt;/h2&gt;

&lt;p&gt;As mentioned, API-first design is a specific methodology for building software systems, where the API is designed and developed before any other system components. APIs are emphasized as a core part of the software development process rather than as an afterthought. In short, the API is considered the backbone of the software, and the rest of the system is built around it.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1592921944818491394-869" src="https://platform.twitter.com/embed/Tweet.html?id=1592921944818491394"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1592921944818491394-869');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1592921944818491394&amp;amp;theme=dark"
  }



 &lt;/p&gt;

&lt;p&gt;API-first design is commonly applied in API-centric products. For example, companies like Stripe or Twilio offer their APIs as a core offering to customers, so they have to design them to be intuitive and user-friendly.&lt;/p&gt;

&lt;p&gt;Companies using or moving to a microservice architecture will also often adopt an API-first design approach. Because APIs are so important in microservices, developing standards and a well-thought-out workflow through API-first design is very important.&lt;/p&gt;

&lt;p&gt;When done well, API-first design offers a number of benefits:&lt;/p&gt;
&lt;h3&gt;
  
  
  Faster Development Times
&lt;/h3&gt;

&lt;p&gt;By designing the API first, development teams can more easily work in parallel on different parts of an application. Having a well-documented API means that teams can stub out specific endpoints to test and build their own systems without having to have a running instance of every API on their machine.&lt;/p&gt;

&lt;p&gt;Similarly, this improves coordination between frontend and backend teams. Frontend developers can build based on the assumption that the backend will adhere to the established documentation, allowing backend developers to work in parallel with them.&lt;/p&gt;

&lt;p&gt;Finally, API-first design makes it easier to reuse endpoints and logic throughout the system. For example, if you’re building an e-commerce application, several parts of the application may need to estimate shipping costs (e.g., pricing page, checkout workflow, returns workflow, invoice generation, etc.). If there’s a single, documented endpoint available, you can ensure that each time it is called, the results will be the same.&lt;/p&gt;
&lt;h3&gt;
  
  
  Improved Developer Experience
&lt;/h3&gt;

&lt;p&gt;It’s often easy to tell when a system wasn’t built with the API in mind because it uses clunky or non-standard endpoints. For example, I recently ran across an API that used the following endpoint to edit a user object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST http://api.example.com/v1/user/edit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this approach technically works, it’s not common. Typically, in a REST API, modification of an object &lt;a href="https://restfulapi.net/rest-put-vs-post/" rel="noopener noreferrer"&gt;would use a &lt;code&gt;PUT&lt;/code&gt; or &lt;code&gt;PATCH&lt;/code&gt; request and include the object’s ID in the URL&lt;/a&gt;. So, consumers of this API must now very carefully read through all the documentation to be sure they use your API properly.&lt;/p&gt;

&lt;p&gt;Whether API consumers are internal or external, systems designed with the API in mind first will almost always provide a better experience to developers. They’re more likely to use established standards which make them much easier and less frustrating to use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better Collaboration and Communication
&lt;/h3&gt;

&lt;p&gt;Ultimately, all the advantages of API-first design come down to making communication and collaboration better.&lt;/p&gt;

&lt;p&gt;When your API is clearly defined and agreed upon up-front, multiple teams can work in parallel, engineers can move from working with one API to another seamlessly, and errors in the implementation or consumption of APIs are more clear.&lt;/p&gt;

&lt;h3&gt;
  
  
  When is API-First the Wrong Approach?
&lt;/h3&gt;

&lt;p&gt;Just because there are advantages to API-first design doesn’t mean it’s a panacea. For example, if you’re building a traditional server-rendered application without plans to offer an API, adding extra layers is a waste of time. API-first design can also hamper nascent projects that aren’t sure exactly how the data model will look when they’re finished.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://solidstudio.io/blog/origin-of-overengineering" rel="noopener noreferrer"&gt;Overengineering is a common problem in software development&lt;/a&gt;, and API-first design approaches are no different.&lt;/p&gt;

&lt;h2&gt;
  
  
  The API-First Design and Development Process
&lt;/h2&gt;

&lt;p&gt;Now that you've seen some of the advantages an API-first process provides, let's get into the practical aspects—what does API-first design look like?&lt;/p&gt;

&lt;p&gt;As the name implies, API-first design dictates that you plan your API as part of the application development process, but like all software, your API needs to be open to change as the system around it changes.&lt;/p&gt;

&lt;p&gt;Typically, a new API will undergo the following stages:&lt;/p&gt;

&lt;h3&gt;
  
  
  Define
&lt;/h3&gt;

&lt;p&gt;This is the initial stage of the API lifecycle, where you’ll define and establish the API's overall goals, requirements, and constraints. This stage is critical for setting the scope of the project and ensuring that the final API will meet the needs of its intended users and stakeholders.&lt;/p&gt;

&lt;p&gt;At this point, you should consider the technical and service-level requirements, the data format users will prefer (JSON, XML, etc.), the &lt;a href="https://medium.com/back-to-the-napkin/the-next-step-to-build-better-apis-consistent-data-structure-38667444f37e" rel="noopener noreferrer"&gt;data structure&lt;/a&gt;, and the downstream systems that rely on your API. You should also consider the audience for this API. Will it be publicly available? For private or internal use only? Or limited to verified partners?&lt;/p&gt;

&lt;p&gt;Finally, you should define any key roles or processes your team will use while building and maintaining the API. You’ll need to decide on the tools you’re going to use to design and document the API as well as a plan for change management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design
&lt;/h3&gt;

&lt;p&gt;Next, you will outline the API's design and structure. Based on the performance, scalability, security, and other requirements outlined in the &lt;em&gt;Define&lt;/em&gt; stage, you will need to make decisions like whether to use &lt;a href="https://blog.logrocket.com/graphql-vs-grpc-vs-rest-choosing-right-api/" rel="noopener noreferrer"&gt;REST, GraphQL, or gRPC&lt;/a&gt;, how to authenticate and authorize consumers, and how to report and track errors.&lt;/p&gt;

&lt;p&gt;During this stage, you can create API contracts that provide clear guidelines for the API's behavior. Assuming an HTTP API, developers will often use a standard specification like &lt;a href="https://bump.sh/blog/what-is-openapi?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-first-design" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt; or &lt;a href="https://bump.sh/blog/what-is-asyncapi?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-first-design" rel="noopener noreferrer"&gt;AsyncAPI&lt;/a&gt; to define the &lt;a href="https://www.ibm.com/docs/en/amoc/3.0.1?topic=operations-defining-rest-api" rel="noopener noreferrer"&gt;API’s operations (verb and URL)&lt;/a&gt; and response format. Having contracts like this allows developers to properly implement the API, and it lets consumers mock the API so they can build downstream applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Develop and Document
&lt;/h3&gt;

&lt;p&gt;In the next stage, you will implement the API, and create the necessary documentation.&lt;/p&gt;

&lt;p&gt;Traditionally, documentation has been a manual process, but API tooling has come a long way, and now you can use tools like &lt;a href="https://bump.sh/?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-first-design" rel="noopener noreferrer"&gt;Bump.sh&lt;/a&gt; to automatically generate your API documentation from your contract defined during the design phase. This allows your developers to focus on implementing the API and building internal business logic without having to worry if they’re keeping their documentation up to date.&lt;/p&gt;

&lt;p&gt;As in building any web application, you’ll need to make decisions about the internal architecture of the API (framework, language, database, etc.), the ancillary services needed (message queues, notifications, etc.), and deployment options. If you’re in an established organization, many of these decisions might be mandated externally, but in greenfield projects, there’s often a lot of leeway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test
&lt;/h3&gt;

&lt;p&gt;Before deploying an API, it's important to thoroughly test it to ensure that it behaves as expected, meets the outlined spec, and will continue to behave as expected as the API changes. Typically, this includes unit testing, integration testing, and load testing. While &lt;a href="https://www.infoworld.com/article/3286529/test-automation-comes-of-age.html" rel="noopener noreferrer"&gt;automated testing should comprise the bulk of your API tests&lt;/a&gt; you’ll likely want to do some manual QA as well to catch any unexpected behaviors before you launch.&lt;/p&gt;

&lt;p&gt;After launch, testing is equally important, so focus on building repeatable testing practices: run them as part of your CI pipeline, keep an eye on code coverage metrics, and don’t let test debt pile up. As you might imagine, these tests will be invaluable once your API starts changing and growing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secure
&lt;/h3&gt;

&lt;p&gt;While security should have been considered at the design stage, this point is important enough to check again after implementation. You want to prevent any unauthorized use or abuse of your API to ensure that sensitive data is protected. Encryption, access controls, user authentication, and other security measures should all be tested and verified before deployment. All the security checks that can be repeated should also be included in your CI processes so they are conducted continuously.&lt;/p&gt;

&lt;p&gt;Most high-stakes API projects will have penetration tests conducted by internal or external auditors. If you’re new to API security, familiarize yourself with &lt;a href="https://owasp.org/www-project-api-security/" rel="noopener noreferrer"&gt;the OWASP API Security Top 10&lt;/a&gt; and make sure you’re covered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy
&lt;/h3&gt;

&lt;p&gt;After testing and securing the API, you can deploy it for use by its intended audience. Obviously, the specifics of this step vary greatly depending on your tech and infrastructure stack, but most companies use multiple environments to ensure their API can be deployed and that changes don’t cause unintended consequences when they’re released.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observe
&lt;/h3&gt;

&lt;p&gt;Observability has come a long way in the past few years, and modern tools allow you to easily track your API's usage, performance, access logs, and errors. Instrumentation should let you catch issues and help you understand how consumers are using the API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evolve
&lt;/h3&gt;

&lt;p&gt;It is worth noting that this API development lifecycle isn’t a one-time process. Like most software projects, you’ll come back to implement changes frequently, so you’ll need to have a plan for implementing, testing, and announcing those changes.&lt;/p&gt;

&lt;p&gt;Tools like &lt;a href="https://bump.sh/api-change-management?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-first-design" rel="noopener noreferrer"&gt;Bump.sh&lt;/a&gt; can help with this as it can track structural changes to your API to automatically update a &lt;a href="https://keepachangelog.com/en/1.0.0/" rel="noopener noreferrer"&gt;changelog&lt;/a&gt; and trigger a &lt;a href="https://docs.bump.sh/help/api-change-management/webhooks/?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-first-design" rel="noopener noreferrer"&gt;webhook to notify other services&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, this lifecycle isn’t necessarily linear: you may need to move backward before you can move forwards. For example, during the development stage, teams may find that certain requirements must be re-evaluated or redesigned. Or, during the testing stage, they may discover issues that require changes to the API's design or implementation. In such cases, teams may need to go back to a previous stage of the API lifecycle to address these issues before moving forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer API Tools
&lt;/h2&gt;

&lt;p&gt;I’ve hinted at tooling a couple of times in this piece, but because it’s such an important part of building a great API, I’ll dig deeper here. There are a few categories of tools that are important when designing and building APIs, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://bump.sh/blog/the-best-api-documentation-tools-for-dev-teams?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-first-design" rel="noopener noreferrer"&gt;&lt;strong&gt;Documentation tools&lt;/strong&gt;&lt;/a&gt; range from presentation-only tools to automatic doc generation tools. In any case, you’ll definitely need some way to document your API and manage changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mocking tools&lt;/strong&gt; allow you to stub all or part of your API so consumers can work without a deployed version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing tools&lt;/strong&gt; come in many different shapes and sizes but most will allow you to automatically run and call endpoints with various parameters to ensure the results match your expectations.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;API browser&lt;/strong&gt; can be helpful for browsing and troubleshooting endpoints or testing specific requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finding the right mix of tools often comes down to personal preference, cost, and ease of use or implementation. Ultimately, what works for one company might not work for another, so it’s important to evaluate all the options in your unique context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;API-first design is a powerful way of building software that prioritizes APIs and their consumers. Development teams can create better products and more efficient workflows by designing APIs first and then building the rest of the application around them.&lt;/p&gt;

&lt;p&gt;Additionally, by thinking about the API from the beginning of the development process, teams can better anticipate the needs of third-party developers and create a more user-friendly experience for them. Overall, API-first design is a key strategy for creating high-quality, effective APIs that are well-suited to the needs of modern software development.&lt;/p&gt;

&lt;p&gt;Getting your API-first design efforts off the ground can be made easier with Bump.sh. Bump.sh is the simplest way to automatically create API documentation portals for internal, partners, and public APIs. Feel free to look at our &lt;a href="https://bump.sh/users/sign_up?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-first-design" rel="noopener noreferrer"&gt;solution&lt;/a&gt;, and please reach out to us if you have any feedback, comments, or suggestions you'd like to share. We're always listening.&lt;/p&gt;

&lt;p&gt;Author: &lt;a href="https://portal.draft.dev/writers/recHYOn2s7qbIn9lc" rel="noopener noreferrer"&gt;Alex Doukas&lt;/a&gt;&lt;/p&gt;

</description>
      <category>apidesign</category>
      <category>api</category>
      <category>apifirst</category>
      <category>designsystem</category>
    </item>
    <item>
      <title>API Contracts - an Extended Introduction</title>
      <dc:creator>Bump.sh</dc:creator>
      <pubDate>Mon, 12 Jun 2023 15:08:33 +0000</pubDate>
      <link>https://dev.to/bump/api-contracts-an-extended-introduction-4ig3</link>
      <guid>https://dev.to/bump/api-contracts-an-extended-introduction-4ig3</guid>
      <description>&lt;p&gt;An API contract is a document that showcases how an API behaves and how it should be used.&lt;br&gt;
This article is all about API contracts: how they can help your business, the best practices to follow, as well as some practical examples.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Are API Contracts Important?
&lt;/h3&gt;

&lt;p&gt;The purpose of an API contract is to ensure developers using the API can interact with it in a consistent and predictable manner.&lt;/p&gt;

&lt;p&gt;A consistent API contract also helps standardize integration with other systems, reducing misunderstandings and errors.&lt;/p&gt;

&lt;p&gt;It's a useful tool for promoting a shared understanding of your API, easing in changes, and assuring the users of your APIs stability and reliability.&lt;/p&gt;

&lt;p&gt;Having a defined API contract helps streamline processes for both internal and external API users. When multiple external systems or teams are involved, a contract can help avoid misunderstandings and reduce the risk of API usage errors.&lt;/p&gt;

&lt;p&gt;It’s also important in API-first design as downstream teams will often start building mocks of your API before the first version is actually live. Your API development team’s process is also improved with a contract in place, as there's a clear set of guidelines for how the API should behave.&lt;/p&gt;

&lt;p&gt;API contracts can contribute to the security and dependability of the systems that use them. By specifying rules around how different systems should interact, API contracts can help prevent misuse of data and ensure that systems can recover gracefully from errors or failures. Good API contracts will also include details about authorization, request limits, and usage restrictions, which helps users avoid accidentally losing access.&lt;/p&gt;

&lt;p&gt;Finally, almost any API that uses a strict contracting process will have better documentation than one that doesn’t. Often, API contracts are turned directly into documentation, making the lives of development teams much easier.&lt;/p&gt;
&lt;h3&gt;
  
  
  What Are API Contracts ?
&lt;/h3&gt;

&lt;p&gt;API contracts can take many forms, such as a document describing the interface, a formal specification written in a particular language, or a set of code examples illustrating how the API should be used; it can also be written in a combination of formats.&lt;/p&gt;

&lt;p&gt;API Contracts often follow a preexisting specification like &lt;a href="https://spec.openapis.org/oas/latest.html" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt;, &lt;a href="https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md" rel="noopener noreferrer"&gt;gRPC&lt;/a&gt;, &lt;a href="https://spec.graphql.org/October2021/" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt;, &lt;a href="https://www.asyncapi.com/docs/reference/specification/v2.0.0" rel="noopener noreferrer"&gt;AsyncAPI&lt;/a&gt;, or &lt;a href="https://apiblueprint.org/documentation/specification.html" rel="noopener noreferrer"&gt;Blueprint&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using an established standard helps new developers working with your contract learn it faster and it helps your development team save time on creating and maintaining the contract. Most standard come with a set of tools and a publicly available community which gives them the advantage of almost always being better than coming up with your own API contract from scratch.&lt;br&gt;
These contracts typically set out information such as the API's expected behavior, data formats, authorization and authentication processes, error handling, and limitations. Seeing how the contract changes over time can also help users understand changes to your API as new versions are released.&lt;/p&gt;

&lt;p&gt;It may include details about the specific endpoints (i.e., URLs) that can be called, the parameters that can be passed to those endpoints, and the responses that will be returned. Some API contracts may also include information about authentication and authorization, error handling, and other details that are key to proper integration.&lt;/p&gt;
&lt;h3&gt;
  
  
  What Should You Consider When Designing an API Contract?
&lt;/h3&gt;

&lt;p&gt;Here are some basic concepts to keep in mind while designing your API contract:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep it simple, easy to understand, and consistent:&lt;/strong&gt; In most cases, you should use a predefined specification (as mentioned above) to help users learn and integrate your API into their applications more quickly while reducing the scope for misunderstandings or errors. A uniform vocabulary and style across the contract can also help developers identify what they need and quickly understand how to use the API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Document all parts of the API:&lt;/strong&gt; This API contract will be a very good place for everyone interacting with your API to have a complete overview of it. The more it is exhaustive, the more they will be able to fully view and understand the structure of your API. Including elements such as inputs, outputs, error codes, etc. is enormously helpful in the implementation process. Examples are also beneficial as they offer a clear understanding of how the API works and how to incorporate it into applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Thoroughly test the API against the contract:&lt;/strong&gt; You should test the implementation of your API against the stated contract before release, and provide means of reporting changes - especially breaking ones - or inconsistencies as the API evolves. This means your contract should be in a format allowing your QA process to read and validate against it. Ideally, the testing process should be automated so your API can be validated during the &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration" rel="noopener noreferrer"&gt;continuous integration&lt;/a&gt; process each time changes are made.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  API Contracts: Best Practices
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Defining the Expected Behavior of the API
&lt;/h3&gt;

&lt;p&gt;At a minimum, your API contract should showcase the expected behavior of your API and its endpoints as well as explore details about how an application will call the API. Here's an excerpt of an API contract showcasing the API behavior and the data you can get from it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
GET /weather

Input parameters:
- location (string): The location for which to retrieve weather information (e.g. "New York, NY")
- version (string): The version of the API to use (e.g. "v1", "v2")

Output:
- temperature (float): The current temperature in degrees Fahrenheit
- condition (string): A description of the current weather conditions (e.g. "sunny", "cloudy", "rainy")

Example usage:

GET /weather?location=New%20York,%20NY&amp;amp;version=v2

Output:
{
  "temperature": 72.5,
  "condition": "sunny"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[&lt;em&gt;Representation of the behavior of the API&lt;/em&gt;]&lt;/p&gt;

&lt;p&gt;Your contract should always provide details on how your users can utilize your API. This excerpt, for example, specifies that the API can be accessed using a GET request to the &lt;code&gt;/weather&lt;/code&gt; endpoint and that it takes an input parameter, &lt;code&gt;location&lt;/code&gt;, which is a string representing the location for which to retrieve weather information. The second input parameter, &lt;code&gt;version&lt;/code&gt;, is also a string and represents the version of the API the user would like to interact with.&lt;/p&gt;

&lt;p&gt;It also makes clear that the API returns a JSON object with two fields: temperature, which is a float representing the current temperature in degrees Fahrenheit, and condition, which is a string describing the current weather conditions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specifying the Contract and API Version
&lt;/h3&gt;

&lt;p&gt;It is common, on an API lifecycle, to see changes to the API behavior itself.  As an API grows, changes will be made to the current version of the API. The contract is a good place to communicate to your users and API consumers about the changes in your API and how to keep using your API service after the change applies.&lt;/p&gt;

&lt;p&gt;If you need to make a breaking change or your API grows and changes so much that you have the need to release a new version of it, you will need to create a new contract. Each version of your API should possess its own. And ideally each version of the API has their own documentation.&lt;/p&gt;

&lt;p&gt;Your contract should note which API version it services.&lt;br&gt;
It should also display the API contract version, which can be different from your API version. For instance, in the OpenAPI spec, an &lt;a href="https://spec.openapis.org/oas/v3.1.0#fixed-fields-0" rel="noopener noreferrer"&gt;info.version&lt;/a&gt; field is used to explicitly state the version or revision of the API contract in use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;info:
  description: "A simple API example."
  title: "Example"
  version: "1.2"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[&lt;em&gt;An example of how to specify the version according to the Open API spec&lt;/em&gt;]&lt;/p&gt;

&lt;p&gt;As your API contract and API versions change, you should ensure these are noted in your changelog or release notes. This helps users know when a breaking release is made and what they need to do to keep their implementation working.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document Data Formats, Limitations, and Restrictions
&lt;/h3&gt;

&lt;p&gt;Your API contract should accurately document the peculiarities and formats of data that a user might receive from API calls. &lt;a href="https://medium.datadriveninvestor.com/why-data-normalization-is-still-a-huge-challenge-for-organizations-6e0d5f5721d" rel="noopener noreferrer"&gt;Data normalization is notoriously difficult&lt;/a&gt;, so you want to help your API’s users as much as possible by giving them clear descriptions of return types and input expectations.&lt;/p&gt;

&lt;p&gt;It should also set out the limitations that the user should be aware of as they implement the API — for example, rate limits, availability schedules, and requirements for access to certain data. If these constraints are not clear it can be frustrating for users who suddenly hit unexpected limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Contract at the Age of Automation
&lt;/h2&gt;

&lt;p&gt;Your API contract does not only allow you all the things listed above, it’s also a good piece to add in your automations.&lt;/p&gt;

&lt;p&gt;A common practice is to have your unit tests results tested against the API contract. You can make your &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration" rel="noopener noreferrer"&gt;CI&lt;/a&gt; process fail if the behavior of the API is not matching the expectations of the contract, and you can also analyze changes (including breaking changes) directly from the CI as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next for your API Contract ?
&lt;/h2&gt;

&lt;p&gt;Once you’ve defined your contract and implemented your API, you can use a tool to &lt;a href="https://bump.sh/api-documentation?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-contracts" rel="noopener noreferrer"&gt;create the user-facing documentation&lt;/a&gt;. In addition to documentation generation based on API contract documents, Bump.sh also integrates with your CI pipeline to ensure that changes to the API are noted in the documentation upon each release.&lt;/p&gt;

&lt;p&gt;If you’re interested in learning more about API design or development, be sure to check out the &lt;a href="https://bump.sh/blog?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-contracts" rel="noopener noreferrer"&gt;Bump.sh blog&lt;/a&gt;, or &lt;a href="https://bump.sh/users/sign_up?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-contracts" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt; to see how Bump.sh can help you generate user documentation more easily.&lt;/p&gt;

</description>
      <category>apicontract</category>
      <category>documentation</category>
      <category>api</category>
      <category>asyncapi</category>
    </item>
    <item>
      <title>Creating Better API Architecture Diagrams</title>
      <dc:creator>Bump.sh</dc:creator>
      <pubDate>Mon, 12 Jun 2023 14:59:34 +0000</pubDate>
      <link>https://dev.to/bump/creating-better-api-architecture-diagrams-7in</link>
      <guid>https://dev.to/bump/creating-better-api-architecture-diagrams-7in</guid>
      <description>&lt;p&gt;Architecture diagrams are essential in the API development process. They provide a map of how different systems interact to help software teams manage and maintain them, and they provide insight into the architect’s vision for the entire system. Along with other elements like interactive API portals, API architecture diagrams also help enrich your API’s documentation.&lt;/p&gt;

&lt;p&gt;This guide will share more about the various types of API architecture diagrams and some tips for creating them. You will see several examples of these diagrams and learn about the utility of UML for modeling them. Finally, you’ll get some best practices for creating architecture diagrams as a supplement to your API documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are API Architecture Diagrams and Do You Need Them?
&lt;/h2&gt;

&lt;p&gt;API architecture diagrams are visual representations of the structure and interactions of the components of an API. They can help developers and architects plan the interface structure, users understand the intended use of the API, and they can also help QA engineers better test and debug the API.&lt;/p&gt;

&lt;p&gt;Typically, an API architecture diagram will &lt;strong&gt;identify the various API components, their relationships with each other, and the data flow between them&lt;/strong&gt;, but as you’ll see in this piece, there are many types of API diagrams worth looking at.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1356308080389193728-149" src="https://platform.twitter.com/embed/Tweet.html?id=1356308080389193728"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1356308080389193728-149');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1356308080389193728&amp;amp;theme=dark"
  }



 &lt;/p&gt;

&lt;p&gt;Unfortunately, creating a good API architecture diagram takes time. As the author of the Tweet above points out, this particular diagram took 10 hours of work to complete. So, creating diagrams like this can be helpful, but your engineering and documentation teams will need to make time to get them right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of API Architecture Diagrams
&lt;/h2&gt;

&lt;p&gt;Depending on the API you’re documenting, the communication protocols you’re using, the complexity of the system, and the goals of the architecture diagram, you may diagram the API differently. In this post, I’ll primarily focus on diagramming &lt;a href="https://en.wikipedia.org/wiki/Representational_state_transfer" rel="noopener noreferrer"&gt;REST&lt;/a&gt; APIs, but the types of API diagrams you can create are basically endless.&lt;/p&gt;

&lt;p&gt;That said, here are a few interesting common types of API architecture diagrams:&lt;/p&gt;

&lt;h3&gt;
  
  
  Sequence Diagrams
&lt;/h3&gt;

&lt;p&gt;One way to use an API diagram is to illustrate a specific workflow that consumers need to know about. A sequence diagram often includes the HTTP verb (&lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, or &lt;code&gt;DELETE&lt;/code&gt;) and resource name for each API call in the diagram. They can also be useful for noting any custom calls (like bulk endpoints) that your API offers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j6mojve91nkj1abdtgc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j6mojve91nkj1abdtgc.jpg" alt="API diagram that includes HTTP verb and resource" width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The API diagram above uses the order of arrows to indicate the order in which the calls should be made. Complex workflows like authentication and authorization often require API calls to be made in a very specific order, so API architecture diagrams can help clarify this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kuze8z8xqovywvur9mu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kuze8z8xqovywvur9mu.png" alt="API flow diagram" width="800" height="622"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Example of a REST API sequence diagram with swimlanes.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Service Architecture Diagrams
&lt;/h3&gt;

&lt;p&gt;Another way to use API architecture diagrams is to show how multiple services are connected and integrated with one another.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuedwsr5ek4i977h6ox9u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuedwsr5ek4i977h6ox9u.jpg" alt="API architecture diagram that shows system integration" width="800" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The diagram above shows how an online store’s architecture diagram might look, including the resources, endpoints, and attributes of each resource.&lt;/p&gt;

&lt;p&gt;Service Architecture Diagrams help new users get a “lay of the land” when it comes to your API, meaning they can quickly see how all the resources and data models are related. This can help them plan out their application, especially if they’ll rely on several endpoints or services within your ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Internal API Architecture Diagrams
&lt;/h3&gt;

&lt;p&gt;Finally, your diagram might be focused on illustrating the internal architecture of your system rather than the external.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzx97p1s1d5afmhbxbwqz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzx97p1s1d5afmhbxbwqz.jpg" alt="Internal API architecture diagram" width="689" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These diagrams are useful for other engineers at your company to see how the system is designed so they can better understand errors and debug errors faster. They help new engineers onboard faster, and can serve as a reference point when designing new systems at the company. Finally, they help with internal processes like security audits as knowing all the layers a request goes through before accessing your data can help identify vulnerabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools for Creating API Architecture Diagrams
&lt;/h2&gt;

&lt;p&gt;Now that we have covered some types of API diagrams you might use, the next step is to figure out how to actually create the model for your API architecture diagram. There are many different tools available depending on your preference, team’s experience, and the purpose of your diagrams, but let’s take a look at three.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unified Modeling Language (UML)
&lt;/h3&gt;

&lt;p&gt;Engineers have a range of visual language models they can use to create graphical diagrams of software systems, but one of the most common standards for diagramming is &lt;a href="https://en.wikipedia.org/wiki/Unified_Modeling_Language" rel="noopener noreferrer"&gt;Unified Modeling Language (UML)&lt;/a&gt;. Many developers choose UML because of its:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Widespread use&lt;/strong&gt; - Using a &lt;a href="https://www.omg.org/spec/UML/Current" rel="noopener noreferrer"&gt;standard like UML&lt;/a&gt; ensures that multiple members of your team can pick it up and make modifications to the diagram in the future.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt; - Although the UML has a vast library of symbols and concepts designed explicitly for creating software architecture diagrams, you can also customize its elements to fit whatever technologies your project uses or visual representations you want to create. UML is not limited to object-oriented software modeling, but is also commonly used to explain business processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tooling&lt;/strong&gt; - The popularity of the UML has led to the creation of a number of tools ranging from online tools for creating UML diagrams, to tools for generating code from diagrams. This ever-growing ecosystem of UML tools makes it more convenient than other languages of its kind.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The downside to UML is that you have to learn its way of doing things, so there’s a bit of a learning curve to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mermaid
&lt;/h3&gt;

&lt;p&gt;UML is just one format for diagram design specifications. Another option is to use a code to diagram tool like &lt;a href="https://mermaid.js.org/" rel="noopener noreferrer"&gt;Mermaid&lt;/a&gt;. Mermaid transforms plain-text (&lt;a href="https://en.wikipedia.org/wiki/Markdown" rel="noopener noreferrer"&gt;Markdown&lt;/a&gt; inspired text definitions in this case) into full-fleshed visual diagrams. Their tool is &lt;a href="https://github.com/mermaid-js/mermaid" rel="noopener noreferrer"&gt;open-source and written in JavaScript&lt;/a&gt;, making it easy to customize if you’re so inclined. Advantages include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Use&lt;/strong&gt; - Markdown is a well-established language for developer documentation, and their &lt;a href="https://mermaid.live/edit" rel="noopener noreferrer"&gt;live editor&lt;/a&gt; includes examples to help you get started.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizability&lt;/strong&gt; - In addition to being open-source at its core, Mermaid allows you to build themes on top of the core product or use the API to generate diagrams programmatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrations&lt;/strong&gt; - You can install Mermaid on your own server or embed it directly into your documentation or developer portal, making it one of the most flexible options out there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Downsides to Mermaid could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The default chart and diagram types are limited. As mentioned, you can customize it as much as you want to create new types of diagrams, but that takes a fair bit of work and programming knowledge.&lt;/li&gt;
&lt;li&gt;Mermaid uses &lt;a href="https://mermaid.js.org/intro/n00b-syntaxReference.html" rel="noopener noreferrer"&gt;its own syntax&lt;/a&gt;. Even though it’s based on Markdown as mentioned above, it does take a bit of practice before you’ll be completely used to the tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lucidchart
&lt;/h3&gt;

&lt;p&gt;Another approach to creating API architecture diagrams is using a tool like &lt;a href="https://www.lucidchart.com/pages/" rel="noopener noreferrer"&gt;Lucidchart&lt;/a&gt;, which sort of combines the best of a structured language like UML with an open-ended drawing tool. This makes Lucid good for its:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adaptability&lt;/strong&gt; - With Lucid, you can create your own shared library of diagram elements (or use a standard like UML). These diagram elements can become your team’s visual language and help API diagrams across your entire company look similar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration&lt;/strong&gt; - As a purpose-built team diagramming tool, Lucid allows you to version and share documents with your team or the public.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The downside to Lucid is that it’s a little more complex to learn than a freeform drawing tool and it’s not free. After your 7-day trial, you’ll be paying—as of today—at least $9 per month for an individual account.&lt;/p&gt;

&lt;p&gt;Finally, it’s worth noting that the three options above aren’t mutually exclusive, and there are many other tools you can use to create API architecture diagrams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for API Architecture Diagrams
&lt;/h2&gt;

&lt;p&gt;Once you know what kind of API architecture diagram you need and how you’ll go about creating it, there are still a few design best practices to keep in mind. Even if your diagram is only intended for internal use, making it visually appealing can help people digest the information better and avoid confusion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the Right Type of Diagram
&lt;/h3&gt;

&lt;p&gt;I’ve already discussed a few types of API architecture diagrams above, but it’s worth noting that you need to consider the goals of your diagram before picking the type of diagram you should create. Remember, a good diagram takes time to design and maintain, so don’t do work you don’t need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Think of Accessibility
&lt;/h3&gt;

&lt;p&gt;Clarity is key when designing architecture diagrams. This is especially true for complex API diagrams, so it's a good idea to use contrasting colors and shapes for each type of component. You can play with colors, shapes, and background patterns for each component so they're easier to identify. Keep in mind that not all eyes work the same (for instance &lt;a href="https://www.clintoneye.com/color-blindness.html" rel="noopener noreferrer"&gt;one in 12 men are colorblind&lt;/a&gt;), so high contrast between elements and text is very important. Tools like &lt;a href="https://github.com/michelf/sim-daltonism/" rel="noopener noreferrer"&gt;Sim Daltonism&lt;/a&gt; on osX can help ensure that your diagrams are readable for everyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep it Simple and Avoid Redundancy
&lt;/h3&gt;

&lt;p&gt;Make sure your diagram is as straightforward to understand as possible. Avoid redundant elements or unnecessary complexity like intersecting lines. Also, promote readability by using &lt;a href="https://en.wikipedia.org/wiki/Swimlane" rel="noopener noreferrer"&gt;swimlanes&lt;/a&gt;, leaving enough white space between diagram elements, and maintaining a uniform size of symbols and figures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid Jargon
&lt;/h3&gt;

&lt;p&gt;To promote clarity and readability, it's good practice to use simple, easy-to-understand terms instead of technical jargon. In cases where this isn't possible, at least explain your terms. You can do this by including &lt;a href="https://www.quora.com/What-is-the-difference-between-map-legend-and-map-keys" rel="noopener noreferrer"&gt;a key or legend&lt;/a&gt; along with your diagram.&lt;/p&gt;

&lt;h3&gt;
  
  
  Going Further
&lt;/h3&gt;

&lt;p&gt;As mentioned previously, API diagrams are a great way to help a user understand your API. They're a great addition to the “Getting Started” section you’ll find in a lot of API documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.bump.sh/help/specifications-support/markdown-support/?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-architecture-diagams" rel="noopener noreferrer"&gt;Bump.sh supports markdown&lt;/a&gt; descriptions and helps you share your API architecture diagrams via generated documentation based on an &lt;a href="https://bump.sh/blog/api-contracts-extended-introduction?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-architecture-diagams" rel="noopener noreferrer"&gt;API contract&lt;/a&gt;.&lt;br&gt;
To add an image to any markdown you just need the following syntax &lt;code&gt;![](https://rb.gy/i0zf0)&lt;/code&gt; where the link is a public URL to your image. More on that, brand new image sizing feature and best practices &lt;a href="https://docs.bump.sh/help/specifications-support/markdown-support/#images?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-architecture-diagams" rel="noopener noreferrer"&gt;in the &lt;strong&gt;Images&lt;/strong&gt; section of the documentation&lt;/a&gt;.&lt;br&gt;
It you want to play even more with markdown, the &lt;a href="https://docs.bump.sh/help/specifications-support/markdown-support/#adding-topics-to-your-documentation?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-architecture-diagams" rel="noopener noreferrer"&gt;&lt;code&gt;x-topics&lt;/code&gt; property&lt;/a&gt; makes it easy to add relevant content sections to your documentation for a well-organized, reader-friendly structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, you learned how API architecture diagrams can support your product and documentation efforts. You saw how diagrams can make systems that are easier to understand and maintain, and you learned about a few different types of API architecture diagrams that are available. Finally, you learned about a few tools and best practices for creating API architecture diagrams that are easier to read and maintain.&lt;/p&gt;

&lt;p&gt;Diagrams are just one tool in a developer’s toolbox for providing clarity around their APIs. You’ll also need documentation (which often includes relevant diagrams), an API contract, and a change management system.&lt;/p&gt;

&lt;p&gt;If you’re looking for more ways to provide clarity around your API, check out &lt;a href="https://bump.sh/?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-architecture-diagams" rel="noopener noreferrer"&gt;Bump.sh&lt;/a&gt;. Import API contracts into Bump.sh and automatically generate human-readable documentation, with &lt;a href="https://bump.sh/api-change-management?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-architecture-diagams" rel="noopener noreferrer"&gt;change-tracking&lt;/a&gt; and &lt;a href="https://docs.bump.sh/help/api-change-management/#changes-notification?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-api-architecture-diagams" rel="noopener noreferrer"&gt;notification capabilities&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Author: &lt;a href="https://portal.draft.dev/writers/recNA8hRZSciDpy1O" rel="noopener noreferrer"&gt;Damaso Sanoja&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>tutorial</category>
      <category>architecture</category>
      <category>diagrams</category>
    </item>
    <item>
      <title>Using OpenAPI and AsyncAPI Tags to Better Organize API Endpoints</title>
      <dc:creator>Bump.sh</dc:creator>
      <pubDate>Mon, 12 Jun 2023 14:49:20 +0000</pubDate>
      <link>https://dev.to/bump/using-openapi-and-asyncapi-tags-to-better-organize-api-endpoints-1cbi</link>
      <guid>https://dev.to/bump/using-openapi-and-asyncapi-tags-to-better-organize-api-endpoints-1cbi</guid>
      <description>&lt;p&gt;OpenAPI Tags are a great way to organize the API endpoints in &lt;a href="https://bump.sh/blog/api-contracts-extended-introduction?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-tags-api-endpoints" rel="noopener noreferrer"&gt;your API Contract&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When developing APIs, it's essential to document the API so that other developers, whether internal or external, can use the API effectively. &lt;a href="https://spec.openapis.org/oas/latest.html" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt; and &lt;a href="https://www.asyncapi.com/docs/reference/specification/latest" rel="noopener noreferrer"&gt;AsyncAPI&lt;/a&gt; are open source specifications useful when writing API contracts.&lt;br&gt;
An &lt;a href="https://bump.sh/blog/api-contracts-extended-introduction?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-tags-api-endpoints" rel="noopener noreferrer"&gt;API contract describes the API&lt;/a&gt;, including its endpoints, data structures, and security constraints. When writing these, you can use &lt;a href="https://docs.bump.sh/help/specifications-support/openapi-support/name-and-sort-resources/#group-by-tag" rel="noopener noreferrer"&gt;OpenAPI tags&lt;/a&gt; and &lt;a href="https://www.asyncapi.com/docs/reference/specification/v2.0.0#tagsObject" rel="noopener noreferrer"&gt;AsyncAPI tags&lt;/a&gt; to help you categorize your contract so that it's more readable and easier to understand.&lt;/p&gt;

&lt;p&gt;Let’s see how that works !&lt;/p&gt;
&lt;h2&gt;
  
  
  Tag Example
&lt;/h2&gt;

&lt;p&gt;Typically, OpenAPI and AsyncAPI tags are used to group related endpoints in a meaningful way, such as by business function or logical objects. When using tags, you define an array of tags at the root of your document, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clients&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create, update and retrieve client information.&lt;/span&gt;
    &lt;span class="na"&gt;externalDocs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read more&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://docs.example.com/api/clients&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Notifications&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Manage notifications for the current user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you've created these tags, you can use them to group related endpoints in your API using the &lt;code&gt;tags&lt;/code&gt; property on the endpoint as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;/clients&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Clients&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retrieve all clients.&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retrieves all clients the user has access to.&lt;/span&gt;
  &lt;span class="na"&gt;/notifications/unread&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Notifications&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retrieves all unread notifications.&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retrieves all unread notifications for the current user.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also apply multiple tags to an endpoint, as shown in the code snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;/clients/{clientId}/notifications&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Clients&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Notifications&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retrieve all the notifications for a particular client.&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retrieves all the notifications for a particular client that the user has access to.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benefits of OpenAPI and AsyncAPI Tags
&lt;/h2&gt;

&lt;p&gt;Tags are a powerful tool for improving the usability of your API contract. Below are some of the ways using tags can help keep your API contract organized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tags Can Describe Endpoint Groups
&lt;/h3&gt;

&lt;p&gt;When specifying your tags in the root level of your API contract, you can give context to the tag using the &lt;code&gt;description&lt;/code&gt; property.&lt;br&gt;
Let’s take &lt;a href="https://bump.sh/demo/doc/bump?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-tags-api-endpoints" rel="noopener noreferrer"&gt;Bump.sh API documentation&lt;/a&gt;. Here is how the &lt;code&gt;Diffs&lt;/code&gt; tag is created and described in &lt;a href="https://developers.bump.sh" rel="noopener noreferrer"&gt;Bump.sh API Contract&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diffs&lt;/span&gt;
      &lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diff summary of changes in the API&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The documentation will show the &lt;code&gt;Diffs&lt;/code&gt; property like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxad8u7m8gr2mn953d8is.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxad8u7m8gr2mn953d8is.png" alt="Diff attribute in the generated API documentation" width="800" height="199"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bump.sh/demo/doc/bump/group/endpoint-diffs?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-tags-api-endpoints" rel="noopener noreferrer"&gt;&lt;em&gt;See it live&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that &lt;a href="https://docs.bump.sh/help/specifications-support/markdown-support/" rel="noopener noreferrer"&gt;you can use markdown&lt;/a&gt; in the &lt;code&gt;description&lt;/code&gt; field to better describe your tags.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tags Can Link to Additional Documentation
&lt;/h3&gt;

&lt;p&gt;While the &lt;code&gt;description&lt;/code&gt; property is excellent for giving a little more information about a specific tag, you might need to provide additional documentation if the business logic or object represented by the tag is complex and requires further explanation. Let’s take our Diffs example from above. You can provide a link to an external web page where you offer a more detailed explanation using the &lt;code&gt;externalDocs&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;In the code snippet below, the &lt;code&gt;externalDocs&lt;/code&gt; property provides a link to a URL using the &lt;code&gt;url&lt;/code&gt; property. A description for the URL can also be specified using the &lt;code&gt;description&lt;/code&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diffs&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diff summary of changes in the API&lt;/span&gt;
    &lt;span class="na"&gt;externalDocs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;More details about Diff&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://docs.bump.sh/help/api-change-management/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you generate API documentation for the API contract above, you'll see the link rendered like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftuj8fgtcvmhsofyz6j6e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftuj8fgtcvmhsofyz6j6e.png" alt="How the externalDocs property is displayed in generated API documentation." width="700" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tags Can Order Endpoint Groups in Documentation
&lt;/h3&gt;

&lt;p&gt;When specifying your OpenAPI or AsyncAPI tags in the root of your API contract, the order in which you list the tags will define the order in which they appear in the generated documentation. This ordering lets you sort the tags meaningfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diffs&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diff summary of changes in the API&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ping&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Monitoring status endpoints&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Previews&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Preview for documentation file&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Versions&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy your API contracts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validations&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check &amp;amp; validate your API contracts&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Hubs&lt;/span&gt;
    &lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Interact with your Hubs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you generate API documentation, you'll notice the documentation orders the endpoint groups in the same way:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh22fsogfzv75jvwj4mf2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh22fsogfzv75jvwj4mf2.png" alt="How tags are ordered in generated API documentation" width="800" height="199"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bump.sh/demo/doc/bump?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-tags-api-endpoints" rel="noopener noreferrer"&gt;&lt;em&gt;See it live&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that &lt;a href="https://docs.bump.sh/help/specifications-support/openapi-support/name-and-sort-resources/#group-by-tag" rel="noopener noreferrer"&gt;Bump.sh helps you order your endpoints and webhooks&lt;/a&gt; using a "Group by tag" operation. It is actually the default behaviour of Bump.sh when you have these tags defined and have not selected an other sorting option for your Bump.sh API documentation.&lt;/p&gt;

&lt;p&gt;Now that you understand what tags are and their benefits, you'll see some best practices you should follow when using OpenAPI and AsyncAPI tags in API contracts.&lt;/p&gt;
&lt;h2&gt;
  
  
  OpenAPI Tags Best Practices
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Tag Everything
&lt;/h3&gt;

&lt;p&gt;When using tags, make sure you tag all your endpoints.&lt;br&gt;
Notice how all diff-related endpoints are tagged with the &lt;code&gt;Diffs&lt;/code&gt; tag in this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;/diffs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Diffs&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create a diff&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;/diffs/{id}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Diffs&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fetch detailed information from an existing diff&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can &lt;a href="https://developers.bump.sh/group/endpoint-diffs" rel="noopener noreferrer"&gt;see live&lt;/a&gt; how they are all available under the section Diffs. By clicking the name of the section in the left menu, the tagged endpoints will show up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vlxa9ir1z80e4gnf1f7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vlxa9ir1z80e4gnf1f7.png" alt="tagged endpoints on Bump.sh documentation" width="478" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Untagged endpoints will not show up under any big section represented by a tag of your documentation generated by Bump.sh&lt;/p&gt;

&lt;p&gt;To ensure your endpoints remain logically grouped and ordered, always tag every endpoint, even if it means creating a tag for a single endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make Every Tag Unique
&lt;/h3&gt;

&lt;p&gt;When defining the list of tags in the root of your API contract, make sure not to duplicate tag names. Since the tag's &lt;code&gt;name&lt;/code&gt; property links an endpoint to a tag, duplicate names are likely to confuse developers looking at the API contract.&lt;/p&gt;

&lt;p&gt;The code snippet below contains the root Tag Object in an API contract. Notice how the &lt;code&gt;Validations&lt;/code&gt; tag has been duplicated, and the second definition contains a different description to the first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diffs&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diff summary of changes in the API&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Versions&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy your API contracts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validations&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check &amp;amp; validate your API contracts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Hubs&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Interact with your Hubs&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Documentation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;change"&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check &amp;amp; validate your API contracts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validations&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validate your API status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These duplicate tags would confuse anyone trying to understand your API contract, as they wouldn't know which of the two tag definitions an endpoint belongs to.&lt;/p&gt;

&lt;p&gt;Instead, make sure you define and describe every tag only once in the root Tag Object, like in the snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diffs&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diff summary of changes in the API&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Versions&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy your API contracts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validations&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check &amp;amp; validate your API contracts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Hubs&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Interact with your Hubs&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Documentation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;change"&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check &amp;amp; validate your API contracts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Define All Your OpenAPI Tags in the Root Tag Object
&lt;/h3&gt;

&lt;p&gt;The OpenAPI specification &lt;a href="https://swagger.io/specification/#:~:text=A%20list%20of,MUST%20be%20unique" rel="noopener noreferrer"&gt;doesn't require you to define all your tags in the root Tag Object of your API contract&lt;/a&gt;. This means you can add a tag to an endpoint without listing it in the root Tag Object, but this is a bad idea. You won't be able to control what order the OpenAPI tags should appear in, and you won't be able to add a description or provide a link to external documentation for that tag. It can also confuse developers browsing your API contract as they won't see a list of all the tags used in the API contract.&lt;/p&gt;

&lt;p&gt;As an example, consider the code snippet below where the &lt;code&gt;Previews&lt;/code&gt; and the &lt;code&gt;Ping&lt;/code&gt; tags has not been included in the root Tag Object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diffs&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diff summary of changes in the API&lt;/span&gt;
  &lt;span class="c1"&gt;# Missing Previews tag&lt;/span&gt;
  &lt;span class="c1"&gt;# Missing Ping tag&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Versions&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy your API contracts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validations&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check &amp;amp; validate your API contracts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Hubs&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Interact with your Hubs&lt;/span&gt;



&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;/diffs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Diffs&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;/diffs/{id}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Diffs&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;/hubs/{hub_id_or_slug}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Hubs&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;/versions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Versions&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;/validations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Validations&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;/previews&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Previews&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;/previews/{preview_id}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Previews&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;/versions/{version_id}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Versions&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;/ping&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Ping&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you generate the documentation, notice how the &lt;code&gt;Previews&lt;/code&gt; and &lt;code&gt;Ping&lt;/code&gt; sections are at the bottom of the list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmystlfq51gm5xjao77tk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmystlfq51gm5xjao77tk.png" alt="Previews and Ping sections displayed at the bottom" width="800" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This incorrect ordering and lack of description will make this section much harder to understand for a developer consuming your API.&lt;/p&gt;

&lt;p&gt;On the other hand, notice how every endpoint in the API contract below has a tag also defined in the root Tag Object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diffs&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Diff summary of changes in the API&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ping&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check the API status&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Previews&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Preview changes to an API Documentation&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Versions&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy your API contracts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validations&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check &amp;amp; validate your API contracts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Hubs&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Interact with your Hubs&lt;/span&gt;



&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;/diffs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Diffs&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;/diffs/{id}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Diffs&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;/hubs/{hub_id_or_slug}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Hubs&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;/versions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Versions&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;/validations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Validations&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;/previews&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Previews&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;/previews/{preview_id}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Previews&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;/versions/{version_id}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Versions&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;/ping&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;Ping&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By doing this, your documentation will display the endpoint groups in the correct order along with the tag’s description.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh22fsogfzv75jvwj4mf2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh22fsogfzv75jvwj4mf2.png" alt="Generated documentation with every tag described in the root Tag Object" width="800" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, you learned more about OpenAPI and AsyncAPI tags and their value in an API contract. You also learned that you can add descriptions and external documentation links to the tag. This article has also shown you some best practices to follow when using tags that can improve the quality of your generated documentation.&lt;/p&gt;

&lt;p&gt;Bump.sh &lt;a href="https://bump.sh/openapi?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-tags-api-endpoints" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt; and &lt;a href="https://bump.sh/asyncapi?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-tags-api-endpoints" rel="noopener noreferrer"&gt;AsyncAPI documentation generator&lt;/a&gt; implement tags to help you keep your API documentation organized. Bump also &lt;a href="https://bump.sh/api-change-management?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-tags-api-endpoints" rel="noopener noreferrer"&gt;detects and notifies you of breaking changes&lt;/a&gt; when deploying a new version of your API.&lt;/p&gt;

&lt;p&gt;Bump.sh is the simplest way to automatically create &lt;a href="https://bump.sh/api-catalog?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-tags-api-endpoints" rel="noopener noreferrer"&gt;API portals for internal, partner, and public APIs&lt;/a&gt;. Discover it by &lt;a href="https://bump.sh/users/sign_up?utm_source=devto&amp;amp;utm_medium=devto-blog&amp;amp;utm_campaign=blog-tags-api-endpoints-signups" rel="noopener noreferrer"&gt;signing up&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Author: Ivan Kahl&lt;/p&gt;

</description>
      <category>openapi</category>
      <category>asyncapi</category>
      <category>tutorial</category>
      <category>api</category>
    </item>
  </channel>
</rss>
