Publishing OAS-Based API Doc on GitHub Pages

Published: (March 15, 2026 at 06:00 PM EDT)
4 min read
Source: Dev.to

Source: Dev.to

Environment

ComponentVersion
OSmacOS Sequoia 15.1.1
CPUApple M4
ShellZsh 5.9
cURL8.11.1
Docker Desktop4.37.2
GitHub API2022‑11‑28

Project Structure

├── docker
│   ├── .env
│   └── docker-compose.yml
├── index.html
├── nginx.conf
└── openapi
    └── openapi.yml

Just a sample.

OpenAPI Specification (openapi/openapi.yml)

openapi: 3.0.3
info:
  title: Sample API
  version: 1.0.0
paths:
  /hello:
    get:
      summary: Hello World Request
      responses:
        "200":
          description: OK
          content:
            text/plain:
              schema:
                type: string
                example: "Hello, World!"

Most of the content is the same as what is written here.

Swagger UI (index.html)

<!DOCTYPE html>
<html>
<head>
  <title>SwaggerUI</title>
  <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist/swagger-ui.css" />
</head>
<body>
  <div id="swagger-ui"></div>
  <script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
  <script>
    window.onload = () => {
      window.ui = SwaggerUIBundle({
        url: './openapi/openapi.yml',
        dom_id: '#swagger-ui'
      });
    };
  </script>
</body>
</html>

Updating the URL to a relative path

window.onload = () => {
  window.ui = SwaggerUIBundle({
    // before
    // url: 'https://petstore3.swagger.io/api/v3/openapi.json',
    // after
    url: './openapi/openapi.yml',
  });
};

Using the latest Swagger UI version

(Add the latest Swagger UI assets as shown above.)

Redoc (redoc.html)

<!DOCTYPE html>
<html>
<head>
  <title>Redoc</title>
  <style>
    body {
      margin: 0;
      padding: 0;
    }
  </style>
</head>
<body>
  <redoc spec-url="./openapi/openapi.yml"></redoc>
  <script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"></script>
</body>
</html>

Updating the spec-url to a relative path

<redoc spec-url="./openapi/openapi.yml"></redoc>

Pinning a specific Redoc version (optional)

<script src="https://cdn.redoc.ly/redoc/2.0.0-rc.56/bundles/redoc.standalone.js"></script>

Nginx Configuration (nginx.conf)

server {
    listen 80;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
}
  • The default HTTP port is 80.
  • The Nginx server runs inside a Docker container.

Docker Compose (docker/docker-compose.yml)

# Set the host port you want Nginx to be reachable on
# e.g. HOST_PORT=8080
# export HOST_PORT=8080   #  **Prerequisite:** A **Personal Access Token (Classic)** with the `repo` scope.

# Fill in your values
PERSONAL_ACCESS_TOKEN=""
OWNER=""
REPO=""
BRANCH=""

1️⃣ Make the repository public (required for GitHub Pages on a free plan)

# Option A – set `private` to false
curl -L -X PATCH \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $PERSONAL_ACCESS_TOKEN" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "https://api.github.com/repos/$OWNER/$REPO" \
  -d '{"private": false}'
# Option B – set visibility to public
curl -L -X PATCH \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $PERSONAL_ACCESS_TOKEN" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "https://api.github.com/repos/$OWNER/$REPO" \
  -d '{"visibility": "public"}'

2️⃣ Activate GitHub Pages

curl -L -X POST \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $PERSONAL_ACCESS_TOKEN" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "https://api.github.com/repos/$OWNER/$REPO/pages" \
  -d '{
        "source": {
          "branch": "'"$BRANCH"'",
          "path": "/"
        }
      }'

Replace $BRANCH with the branch you want GitHub Pages to serve (e.g., main or gh-pages).

After the request succeeds, your OpenAPI preview will be publicly available at:

https://<your-username>.github.io/<repo>/

Enable GitHub Pages

curl -L -X POST \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $PERSONAL_ACCESS_TOKEN" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "https://api.github.com/repos/$OWNER/$REPO/pages" \
  -d "{
        \"build_type\": \"legacy\",
        \"source\": {
          \"branch\": \"$BRANCH\",
          \"path\": \"/\"
        }
      }"

Check the build status

curl -L -X GET \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $PERSONAL_ACCESS_TOKEN" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "https://api.github.com/repos/$OWNER/$REPO/pages/builds/latest"

If GitHub Pages is already enabled, a 409 Conflict error will be returned.

Request‑body quoting

Since the BRANCH variable is used to specify the branch, the request body must use double quotes for JSON.

Soft quoting (double‑quoted JSON)

BRANCH="main"

curl -L -d "{
        \"build_type\": \"legacy\",
        \"source\": {
          \"branch\": \"$BRANCH\",
          \"path\": \"/\"
        }
      }"

Hard quoting (single‑quoted JSON)

curl -L -d '{
        "build_type": "legacy",
        "source": {
          "branch": "main",
          "path": "/"
        }
      }'

Both produce the same payload; the hard‑quoted version is easier to read.

Retrieve the GitHub Pages URL

curl -L \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $PERSONAL_ACCESS_TOKEN" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "https://api.github.com/repos/$OWNER/$REPO/pages"

The response contains the html_url property, which holds the published site URL.

Unpublish GitHub Pages

curl -L -X DELETE \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $PERSONAL_ACCESS_TOKEN" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "https://api.github.com/repos/$OWNER/$REPO/pages"

Sending the same request as when activating the site (but with -X DELETE) removes the published site.

Additional Resources

  • Swagger UI – Interactive API documentation.
  • ReDoc – Alternative API documentation UI.

Note: This publishing procedure does not depend on the number of OAS files. Even if an OAS definition is split across multiple files, you can follow the same steps to publish the documentation.

0 views
Back to Blog

Related posts

Read more »