Publishing OAS-Based API Doc on GitHub Pages
Source: Dev.to
Environment
| Component | Version |
|---|---|
| OS | macOS Sequoia 15.1.1 |
| CPU | Apple M4 |
| Shell | Zsh 5.9 |
| cURL | 8.11.1 |
| Docker Desktop | 4.37.2 |
| GitHub API | 2022‑11‑28 |
Project Structure
├── docker
│ ├── .env
│ └── docker-compose.yml
├── index.html
├── nginx.conf
└── openapi
└── openapi.ymlJust 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.