Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      The Value-Driven AI Roadmap

      September 9, 2025

      This week in AI updates: Mistral’s new Le Chat features, ChatGPT updates, and more (September 5, 2025)

      September 6, 2025

      Designing For TV: Principles, Patterns And Practical Guidance (Part 2)

      September 5, 2025

      Neo4j introduces new graph architecture that allows operational and analytics workloads to be run together

      September 5, 2025

      Lenovo Legion Go 2 specs unveiled: The handheld gaming device to watch this October

      September 10, 2025

      As Windows 10 support ends, users weigh costly extended security program against upgrading to Windows 11

      September 10, 2025

      Lenovo’s Legion Glasses 2 update could change handheld gaming

      September 10, 2025

      Is Lenovo’s refreshed LOQ tower enough to compete? New OLED monitors raise the stakes at IFA 2025

      September 10, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      External Forces Reshaping Financial Services in 2025 and Beyond

      September 10, 2025
      Recent

      External Forces Reshaping Financial Services in 2025 and Beyond

      September 10, 2025

      Why It’s Time to Move from SharePoint On-Premises to SharePoint Online

      September 10, 2025

      Apple’s Big Move: The Future of Mobile

      September 10, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Lenovo Legion Go 2 specs unveiled: The handheld gaming device to watch this October

      September 10, 2025
      Recent

      Lenovo Legion Go 2 specs unveiled: The handheld gaming device to watch this October

      September 10, 2025

      As Windows 10 support ends, users weigh costly extended security program against upgrading to Windows 11

      September 10, 2025

      Lenovo’s Legion Glasses 2 update could change handheld gaming

      September 10, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»How to Automate API Documentation Updates with GitHub Actions and OpenAPI Specifications

    How to Automate API Documentation Updates with GitHub Actions and OpenAPI Specifications

    September 10, 2025

    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

    • How to Create the OpenAPI Specification

    • How to Test the API Spec Locally

      • Install tools

      • Create a landing page

      • Validate Your Spec

      • Preview in the Browser

    • How to Push Local Changes to GitHub

    • How to Set Up Your GitHub Actions Workflow

    • How to Set Up GitHub Pages

      • What is GitHub Pages?

      • Setting Up GitHub Pages

    • How to Handle Multiple Versions

      • About the Versions

        • Version 1 (v1)

        • Version 2 (v2)

        • Version 3 (v3)

      • How to Set Up the Versions Locally

      • How to Validate the API Specs

      • How to Update the GitHub Actions Workflow

    • Summary

    Prerequisites

    • Node.js and npm installed.

    • A GitHub account with basic Git knowledge.

    • Visual Studio Code Editor.

    • Basic knowledge of documentation and OpenAPI.

    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.

    A preview of the API Specification in a Html page

    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 affect spec/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 the gh-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.

    A preview of the settings tab in the `api-docs` repository

    Under Source, choose:

    • Deploy from branch: gh-pages

    • Folder: / (root)

    A step-by-step preview of the gh-pages and root setup

    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.

    A preview of the API documentation in a hosted GitHub Pages environment

    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 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleHow to Store Data Locally Using Hive in Flutter
    Next Article A data center the size of a power plant — Microsoft’s $17.4B AI engine roars to life

    Related Posts

    Development

    How AI is Redefining Traditional GCC Cost Models for Peak Efficiency

    September 10, 2025
    Development

    How to Store Data Locally Using Hive in Flutter

    September 10, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    Taking an all-in-one PC to Starbucks is certainly a move — what’s the weirdest PC setup you’ve seen someone use in public?

    News & Updates

    CVE-2025-5162 – H3C SecCenter SMP-E1114P02 Remote File Upload Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    SysAid Patches 4 Critical Flaws Enabling Pre-Auth RCE in On-Premise Version

    Security

    Accelerate enterprise AI implementations with Amazon Q Business

    Machine Learning

    Highlights

    News & Updates

    A New “Web” Readiness Report

    April 4, 2025

    The beauty of research is finding yourself on a completely unrelated topic mere minutes from…

    CVE-2023-48726 – Apache Struts Cross-Site Scripting

    May 28, 2025

    AI for the board game Diplomacy

    May 13, 2025

    From drop-out to software architect with Jason Lengstorf [Podcast #167]

    April 4, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.