Maintaining up-to-date API documentation is often one of the biggest pain points for developers and teams. Too often, the API spec changes but the docs lag behind, leaving developers with outdated or inconsistent information. This frustrates consumers of your API and increases support overhead.
This is where automation comes in. By combining OpenAPI specifications with GitHub Actions, you can ensure your documentation is always in sync with your API changes.
OpenAPI acts as the single reference point for your API design, keeping your docs consistent, accurate, and aligned with your API.
GitHub Actions automates the workflow, validating your spec, building docs, and publishing to GitHub Pages in seconds.
This tutorial walks you through a working example of how to use GitHub Actions to auto-update your docs.
Table of Contents
Prerequisites
How to Set Up Your Repository
If you don’t already have one, create a GitHub repository. For this tutorial, I’ll use api-docs
as the repo name.
Then open VSCode and create a folder with the same name.
How to Create the OpenAPI Specification
Inside the folder you just created, create a folder called spec
and add a file named greetings.yaml
with the following content:
<span class="hljs-attr">openapi:</span> <span class="hljs-number">3.0</span><span class="hljs-number">.3</span>
<span class="hljs-attr">info:</span>
<span class="hljs-attr">title:</span> <span class="hljs-string">Greetings</span> <span class="hljs-string">API</span>
<span class="hljs-attr">version:</span> <span class="hljs-number">1.0</span><span class="hljs-number">.0</span>
<span class="hljs-attr">description:</span> <span class="hljs-string">This</span> <span class="hljs-string">is</span> <span class="hljs-string">a</span> <span class="hljs-string">greetings</span> <span class="hljs-string">API</span> <span class="hljs-string">demonstrating</span> <span class="hljs-string">a</span> <span class="hljs-string">simple</span> <span class="hljs-string">greeting</span> <span class="hljs-string">endpoint</span> <span class="hljs-string">with</span> <span class="hljs-string">query</span> <span class="hljs-string">parameters</span> <span class="hljs-string">and</span> <span class="hljs-string">multilingual</span> <span class="hljs-string">support.</span>
<span class="hljs-attr">license:</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">MIT</span>
<span class="hljs-attr">url:</span> <span class="hljs-string">https://opensource.org/licenses/MIT</span>
<span class="hljs-attr">servers:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">url:</span> <span class="hljs-string">https://api.yourdomain.com/v1</span>
<span class="hljs-attr">description:</span> <span class="hljs-string">Production</span> <span class="hljs-string">server(v1)</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">url:</span> <span class="hljs-string">https://staging.yourdomain.com/v1</span>
<span class="hljs-attr">description:</span> <span class="hljs-string">Staging</span> <span class="hljs-string">server(v1)</span>
<span class="hljs-attr">security:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">api_key:</span> []
<span class="hljs-attr">paths:</span>
<span class="hljs-string">/hello:</span>
<span class="hljs-attr">get:</span>
<span class="hljs-attr">summary:</span> <span class="hljs-string">Returns</span> <span class="hljs-string">a</span> <span class="hljs-string">greeting</span>
<span class="hljs-attr">operationId:</span> <span class="hljs-string">getGreeting</span>
<span class="hljs-attr">parameters:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">name</span>
<span class="hljs-attr">in:</span> <span class="hljs-string">query</span>
<span class="hljs-attr">required:</span> <span class="hljs-literal">false</span>
<span class="hljs-attr">description:</span> <span class="hljs-string">Name</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">person</span> <span class="hljs-string">to</span> <span class="hljs-string">greet</span>
<span class="hljs-attr">schema:</span>
<span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
<span class="hljs-attr">example:</span> <span class="hljs-string">Ezinne</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">lang</span>
<span class="hljs-attr">in:</span> <span class="hljs-string">query</span>
<span class="hljs-attr">required:</span> <span class="hljs-literal">false</span>
<span class="hljs-attr">description:</span> <span class="hljs-string">Language</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">greeting</span> <span class="hljs-string">(default</span> <span class="hljs-string">is</span> <span class="hljs-string">English)</span>
<span class="hljs-attr">schema:</span>
<span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
<span class="hljs-attr">enum:</span> [<span class="hljs-string">en</span>, <span class="hljs-string">fr</span>, <span class="hljs-string">es</span>, <span class="hljs-string">ig</span>]
<span class="hljs-attr">example:</span> <span class="hljs-string">en</span>
<span class="hljs-attr">responses:</span>
<span class="hljs-attr">'200':</span>
<span class="hljs-attr">description:</span> <span class="hljs-string">Successful</span> <span class="hljs-string">response</span>
<span class="hljs-attr">content:</span>
<span class="hljs-attr">application/json:</span>
<span class="hljs-attr">schema:</span>
<span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
<span class="hljs-attr">properties:</span>
<span class="hljs-attr">message:</span>
<span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
<span class="hljs-attr">examples:</span>
<span class="hljs-attr">english:</span>
<span class="hljs-attr">value:</span> { <span class="hljs-attr">message:</span> <span class="hljs-string">"Hello, Ezinne!"</span> }
<span class="hljs-attr">french:</span>
<span class="hljs-attr">value:</span> { <span class="hljs-attr">message:</span> <span class="hljs-string">"Bonjour, Ezinne!"</span> }
<span class="hljs-attr">spanish:</span>
<span class="hljs-attr">value:</span> { <span class="hljs-attr">message:</span> <span class="hljs-string">"¡Hola, Ezinne!"</span> }
<span class="hljs-attr">igbo:</span>
<span class="hljs-attr">value:</span> { <span class="hljs-attr">message:</span> <span class="hljs-string">"Ndeewo, Ezinne!"</span> }
<span class="hljs-attr">components:</span>
<span class="hljs-attr">securitySchemes:</span>
<span class="hljs-attr">api_key:</span>
<span class="hljs-attr">type:</span> <span class="hljs-string">apiKey</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">Authorization</span>
<span class="hljs-attr">in:</span> <span class="hljs-string">header</span>
This is a simple spec with multilingual greetings. As your API grows (say more languages or versions), keeping docs in sync manually might get tedious. That’s why automation helps.
How to Test the API Spec Locally
Install tools:
Before setting GitHub Actions, you can test the API Spec locally on your machine by setting up Redocly (used to be called Redoc) and testing it in an HTML environment.
Redocly is a lightweight, customizable tool to render OpenAPI specs as an interactive HTML documentation. It’s ideal for static site deployment which makes it ideal for this scenario.
Install Redoc globally with
npm install -g @redocly/cli
Install http-server globally with
npm install -g http-server
The http-server is a local server you can use to test the doc on your machine before you push to GitHub and deploy to GitHub Pages.
Create a landing page:
In your project, make a docs
folder and add index.html
:
<span class="hljs-meta"><!DOCTYPE <span class="hljs-meta-keyword">html</span>></span>
<span class="hljs-tag"><<span class="hljs-name">html</span>></span>
<span class="hljs-tag"><<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">title</span>></span>API Documentation<span class="hljs-tag"></<span class="hljs-name">title</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>/></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span>></span>
<span class="hljs-tag"></<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">body</span>></span>
<span class="hljs-tag"><<span class="hljs-name">redoc</span> <span class="hljs-attr">spec-url</span>=<span class="hljs-string">"../spec/greetings.yaml"</span>></span><span class="hljs-tag"></<span class="hljs-name">redoc</span>></span>
<span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-tag"></<span class="hljs-name">body</span>></span>
<span class="hljs-tag"></<span class="hljs-name">html</span>></span>
Validate Your Spec:
redocly lint spec/greetings.yaml
You should see this if there are no errors or warnings:
Woohoo! Your API description is valid. 🎉
Note: Validating your API Spec before testing is important as it’ll flag any possible errors. This is because Redocly will fail to run the preview if there are any errors in your spec.
Preview in the browser:
Run http-server
, and you should see this in the terminal:
Starting up http<span class="hljs-literal">-server</span>, serving ./
Available on:
http://<span class="hljs-number">127.0</span>.<span class="hljs-number">0.1</span>:<span class="hljs-number">8080</span>
http://<span class="hljs-number">192.168</span>.x.x:<span class="hljs-number">8080</span>
Hit CTRL<span class="hljs-literal">-C</span> to stop the server
Open http://127.0.0.1:8080/
and navigate to /docs
to see your docs.
How to Push Local Changes to GitHub
After making local changes, you need to set up the API documentation so it can update automatically whenever you make changes.
Run these commands if you are pushing to the repository for the first time:
git init
git add .
git commit <span class="hljs-literal">-m</span> <span class="hljs-string">"first commit"</span>
git branch <span class="hljs-literal">-M</span> main
git remote add origin <your<span class="hljs-literal">-repo</span><span class="hljs-literal">-url</span>>
git push <span class="hljs-literal">-u</span> origin main
How to Set Up Your GitHub Actions Workflow
You can set up your GitHub workflow by creating a few folders.
First, create .github/workflows/
in the api-docs
folder. Then, inside the workflows
folder, create a docs.yml
. This is the workflow file that will serve as a trigger to run validation, generate the HTML with Redocly, and deploy to GitHub Pages at the same time.
<span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">API</span> <span class="hljs-string">Documentation</span> <span class="hljs-string">and</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Pages</span>
<span class="hljs-attr">on:</span>
<span class="hljs-attr">push:</span>
<span class="hljs-attr">branches:</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
<span class="hljs-attr">paths:</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">'spec/greetings.yaml'</span>
<span class="hljs-attr">jobs:</span>
<span class="hljs-attr">build-spec:</span>
<span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
<span class="hljs-attr">permissions:</span>
<span class="hljs-attr">contents:</span> <span class="hljs-string">write</span> <span class="hljs-comment"># needed for gh-pages deployment</span>
<span class="hljs-attr">steps:</span>
<span class="hljs-comment"># 1. Checkout repository</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>
<span class="hljs-comment"># 2. Set up Node.js</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Set</span> <span class="hljs-string">up</span> <span class="hljs-string">Node.js</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v4</span>
<span class="hljs-attr">with:</span>
<span class="hljs-attr">node-version:</span> <span class="hljs-string">'20'</span>
<span class="hljs-comment"># 3. Install Redocly CLI</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Redocly</span> <span class="hljs-string">CLI</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span> <span class="hljs-string">-g</span> <span class="hljs-string">@redocly/cli</span>
<span class="hljs-comment"># 4. Validate OpenAPI spec</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Validate</span> <span class="hljs-string">OpenAPI</span> <span class="hljs-string">Spec</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">redocly</span> <span class="hljs-string">lint</span> <span class="hljs-string">spec/greetings.yaml</span>
<span class="hljs-comment"># 5. Build output directory</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Create</span> <span class="hljs-string">build</span> <span class="hljs-string">directory</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public</span>
<span class="hljs-comment"># 6. Copy spec</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">spec</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public/spec</span> <span class="hljs-string">&&</span> <span class="hljs-string">cp</span> <span class="hljs-string">spec/greetings.yaml</span> <span class="hljs-string">public/spec/</span>
<span class="hljs-comment"># 7. Copy landing page</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">landing</span> <span class="hljs-string">page</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">cp</span> <span class="hljs-string">docs/index.html</span> <span class="hljs-string">public/index.html</span>
<span class="hljs-comment"># 8. Deploy to GitHub Pages</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Pages</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">peaceiris/actions-gh-pages@v4</span>
<span class="hljs-attr">with:</span>
<span class="hljs-attr">github_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
<span class="hljs-attr">publish_dir:</span> <span class="hljs-string">./public</span>
Here’s what’s going on in this code:
Runs when changes are pushed to
main
that affectspec/greetings.yaml
.Checks out the repo code.
Sets up Node.js and installs Redocly.
Validates your OpenAPI spec (so broken specs won’t deploy).
Copies the spec and index page into a
public/
folder.Deploys
public/
to thegh-pages
branch with GitHub Pages.
Since we’re done with local testing, update the file path in the index.html
:
<span class="hljs-meta"><!DOCTYPE <span class="hljs-meta-keyword">html</span>></span>
<span class="hljs-tag"><<span class="hljs-name">html</span>></span>
<span class="hljs-tag"><<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">title</span>></span>API Documentation<span class="hljs-tag"></<span class="hljs-name">title</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>/></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span>></span>
<span class="hljs-tag"></<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">body</span>></span>
<span class="hljs-tag"><<span class="hljs-name">redoc</span> <span class="hljs-attr">spec-url</span>=<span class="hljs-string">"./spec/greetings.yaml"</span>></span><span class="hljs-tag"></<span class="hljs-name">redoc</span>></span> <span class="hljs-comment"><!--update the filepath to match your gh config--></span>
<span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-tag"></<span class="hljs-name">body</span>></span>
<span class="hljs-tag"></<span class="hljs-name">html</span>></span>
This is so the public
directory in the workflow will be able to access it correctly.
This workflow will only run when it detects changes in the API Spec (greetings.yml
). To see the workflow in action, make a minor edit in the greetings.yaml
.
Push the changes to your GitHub repository:
git add .
git commit <span class="hljs-literal">-m</span> <span class="hljs-string">'add changes'</span>
git push
How to Set Up GitHub Pages
What is GitHub Pages?
GitHub Pages is a hosting platform owned by GitHub where you can host websites directly from your GitHub account. This means you can publish static sites on the internet using a GitHub domain and anyone with the website link can access it.
There are other hosting platforms you can use to deploy static websites such as Netlify and Vercel. But using GitHub Pages for this documentation is easier to set up as it’s on the same platform.
Setting up GitHub Pages
Set up GitHub Pages by clicking on the Settings tab in your repository.
Under Source, choose:
Deploy from branch:
gh-pages
Folder:
/ (root)
Then save and wait for the workflow to finish.
Your docs will be live at: https://<username>.github.io/api-docs
.
How to Handle Multiple Versions
What if you had multiple API versions to update? Let’s assume the simple greetings API in this tutorial had more features added to it across different versions. In this case, you can manage the APIs for the different versions in a single page and also build and deploy it automatically.
About the Versions
Version 1 (v1)
This is the starting point which is greetings.yaml
. The API only has a single /hello
endpoint that returns a greeting in four languages (English, French, Spanish, or Igbo).
Version 2 (v2)
In version 2, the API adds create and read features. You can:
Use
POST /hello
to create and save a greeting.Retrieve greetings by their unique ID with
GET /hello/{id}
.
Version 3 (v3)
Version 3 builds on top of v2 by adding an update functionality. Along with creating and retrieving greetings, you can now update an existing greeting using PUT /hello/{id}
.
How to Set Up the Versions Locally
First, create a v1
folder and move the greetings.yaml
file to it. Since we are going to be using versions, you can delete the existing spec
folder.
Then, create a v2
folder and create a greetings-v2.yaml
file. Get the greetings API for version 2 here.
Next, create a v3
folder and add greetings-v3.yaml
file. Get the greetings API for version 3 here.
To follow the same pattern with others, rename the version 1 file to greetings-v1.yaml
. Then update your index.html
to accommodate the other two versions.
<span class="hljs-meta"><!DOCTYPE <span class="hljs-meta-keyword">html</span>></span>
<span class="hljs-tag"><<span class="hljs-name">html</span>></span>
<span class="hljs-tag"><<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">title</span>></span>API Documentation<span class="hljs-tag"></<span class="hljs-name">title</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>/></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">style</span>></span><span class="css">
<span class="hljs-selector-tag">body</span> {
<span class="hljs-attribute">font-family</span>: Arial, sans-serif;
<span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
}
<span class="hljs-selector-tag">header</span> {
<span class="hljs-attribute">background</span>: <span class="hljs-number">#2c3e50</span>;
<span class="hljs-attribute">color</span>: white;
<span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
<span class="hljs-attribute">display</span>: flex;
<span class="hljs-attribute">justify-content</span>: space-between;
<span class="hljs-attribute">align-items</span>: center;
}
<span class="hljs-selector-tag">select</span> {
<span class="hljs-attribute">padding</span>: <span class="hljs-number">0.4rem</span>;
<span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
}
</span><span class="hljs-tag"></<span class="hljs-name">style</span>></span>
<span class="hljs-tag"></<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">body</span>></span>
<span class="hljs-tag"><<span class="hljs-name">header</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h2</span>></span>API Documentation<span class="hljs-tag"></<span class="hljs-name">h2</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"version"</span>></span>Version: <span class="hljs-tag"></<span class="hljs-name">label</span>></span>
<span class="hljs-tag"><<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"version"</span> <span class="hljs-attr">onchange</span>=<span class="hljs-string">"loadSpec()"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"./v1/greetings-v1.yaml"</span>></span>v1<span class="hljs-tag"></<span class="hljs-name">option</span>></span>
<span class="hljs-tag"><<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"./v2/greetings-v2.yaml"</span>></span>v2<span class="hljs-tag"></<span class="hljs-name">option</span>></span>
<span class="hljs-tag"><<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"./v3/greetings-v3.yaml"</span>></span>v3<span class="hljs-tag"></<span class="hljs-name">option</span>></span>
<span class="hljs-tag"></<span class="hljs-name">select</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">header</span>></span>
<span class="hljs-comment"><!-- ReDoc container --></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"redoc-container"</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-comment"><!-- ReDoc script --></span>
<span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">loadSpec</span>(<span class="hljs-params"></span>) </span>{
<span class="hljs-keyword">const</span> version = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"version"</span>).value;
Redoc.init(version, {}, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"redoc-container"</span>));
}
<span class="hljs-comment">// Load default (v1) on first load</span>
<span class="hljs-built_in">window</span>.onload = loadSpec;
</span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-tag"></<span class="hljs-name">body</span>></span>
<span class="hljs-tag"></<span class="hljs-name">html</span>></span>
How to Validate the API Specs
Earlier in this article, I mentioned testing your specification locally. Now that you have two more versions of the greetings API, run the test to highlight and fix any existing errors.
For the version V2:
redocly lint v2/greetings-v2.yaml
For the version V3:
redocly lint v3/greetings-v3.yaml
How to Update the GitHub Actions Workflow
Now that you have three API Spec versions, you need to update your workflow so it will monitor the three spec files and the HTML document for changes, and then push and deploy them to GitHub Pages as well.
Add this to your .github/workflows/docs.yml
:
<span class="hljs-comment"># Name of the workflow</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">and</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">API</span> <span class="hljs-string">Documentation</span>
<span class="hljs-attr">on:</span>
<span class="hljs-attr">push:</span>
<span class="hljs-attr">branches:</span> [ <span class="hljs-string">main</span> ]
<span class="hljs-attr">paths:</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">'docs/index.html'</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">'v1/greetings-v1.yaml'</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">'v2/greetings-v2.yaml'</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">'v3/greetings-v3.yaml'</span>
<span class="hljs-attr">jobs:</span>
<span class="hljs-attr">build-and-deploy:</span>
<span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
<span class="hljs-attr">permissions:</span>
<span class="hljs-attr">contents:</span> <span class="hljs-string">write</span>
<span class="hljs-attr">steps:</span>
<span class="hljs-comment"># 1. Checkout the repository</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">repository</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>
<span class="hljs-comment"># 2. Create build directory</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Create</span> <span class="hljs-string">build</span> <span class="hljs-string">directory</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public</span>
<span class="hljs-comment"># 3. Copy YAML specs into public folder</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">v1</span> <span class="hljs-string">spec</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public/v1</span> <span class="hljs-string">&&</span> <span class="hljs-string">cp</span> <span class="hljs-string">v1/greetings-v1.yaml</span> <span class="hljs-string">public/v1/</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">v2</span> <span class="hljs-string">spec</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public/v2</span> <span class="hljs-string">&&</span> <span class="hljs-string">cp</span> <span class="hljs-string">v2/greetings-v2.yaml</span> <span class="hljs-string">public/v2/</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">v3</span> <span class="hljs-string">spec</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public/v3</span> <span class="hljs-string">&&</span> <span class="hljs-string">cp</span> <span class="hljs-string">v3/greetings-v3.yaml</span> <span class="hljs-string">public/v3/</span>
<span class="hljs-comment"># 4. Copy landing page into public</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">landing</span> <span class="hljs-string">page</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">cp</span> <span class="hljs-string">docs/index.html</span> <span class="hljs-string">public/index.html</span>
<span class="hljs-comment"># 5. Deploy to GitHub Pages</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Pages</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">peaceiris/actions-gh-pages@v4</span>
<span class="hljs-attr">with:</span>
<span class="hljs-attr">github_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
<span class="hljs-attr">publish_dir:</span> <span class="hljs-string">./public</span>
And finally, push the changes and reload the site. This should showcase the updated documentation.
Summary
In this tutorial, you have learned how to auto-update your API docs. We started with a single OpenAPI spec and a basic HTML page rendered by Redocly, and tested it locally. We then set up GitHub Actions to automatically validate the spec, copy the files, and deploy the docs to GitHub Pages. Finally, we extended the setup to handle multiple API versions in one place.
With this workflow, your documentation stays accurate, up-to-date, and hassle-free so every change you make to your API spec goes live when you push the changes.
Source: freeCodeCamp Programming Tutorials: Python, JavaScript, Git & MoreÂ