DEV Community

Kengo Hakomori
Kengo Hakomori

Posted on

Publishing OAS-Based API Doc on GitHub Pages

Environment

Dir Structure

.
├── docker
│   ├── .env
│   └── docker-compose.yml
├── index.html
├── nginx.conf
└── openapi
    └── openapi.yml
Enter fullscreen mode Exit fullscreen mode

openapi/openapi.yml

* Just a sample.

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!"
Enter fullscreen mode Exit fullscreen mode

index.html

Swagger UI

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

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="description" content="SwaggerUI" />
    <title>SwaggerUI</title>
    <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css" />
  </head>
  <body>
    <div id="swagger-ui"></div>
    <script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js" crossorigin></script>
    <script>
      window.onload = () => {
        window.ui = SwaggerUIBundle({
          url: './openapi/openapi.yml',
          dom_id: '#swagger-ui'
        });
      };
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode
  • Updated url to the relative path of the OAS file.

    <html lang="en">
      <body>
        <script>
          window.onload = () => {
            window.ui = SwaggerUIBundle({
              // before
              url: 'https://petstore3.swagger.io/api/v3/openapi.json',
              // after
              url: './openapi/openapi.yml',
            });
          };
        </script>
      </body>
    </html>
    
  • Using latest for version specification is also acceptable.

    <html lang="en">
      <head>
        <!-- before -->
        <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css" />
        <!-- after -->
        <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@latest/swagger-ui.css" />
      </head>
      <body>
        <!-- before -->
        <script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js" crossorigin></script>
        <!-- after -->
        <script src="https://unpkg.com/swagger-ui-dist@latest/swagger-ui-bundle.js" crossorigin></script>
      </body>
    </html>
    

ReDoc

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

<!DOCTYPE html>
<html>
  <head>
    <title>Redoc</title>
    <!-- needed for adaptive design -->
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">

    <!--
    Redoc doesn't change outer page styles
    -->
    <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>
Enter fullscreen mode Exit fullscreen mode
  • Updated spec-url to the relative path of the OAS file.

    <html>
      <body>
        <!-- before -->
        <redoc spec-url='http://petstore.swagger.io/v2/swagger.json'></redoc>
        <!-- after -->
        <redoc spec-url='./openapi/openapi.yml'></redoc>
      </body>
    </html>
    
  • Specifying a specific version is also acceptable.
    The list of acceptable versions should match what is written here.

    <html>
      <body>
        <!-- before -->
        <script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
        <!-- after -->
        <script src="https://cdn.redoc.ly/redoc/v2.0.0/bundles/redoc.standalone.js"> </script>
      </body>
    </html>
    

nginx.conf

This file is used to serve a preview of the OAS file via Nginx.

server {
    listen 80;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
}
Enter fullscreen mode Exit fullscreen mode

docker

The Nginx server runs inside a Docker container.

./.env

HOST_PORT={host-port}
Enter fullscreen mode Exit fullscreen mode

./docker-compose.yml

services:
  nginx:
    image: nginx:1.28.2
    ports:
      - "${HOST_PORT}:80"
    volumes:
      # Serve the preview page.
      - ../index.html:/usr/share/nginx/html/index.html:ro
      # Serve the OAS file.
      - ../openapi:/usr/share/nginx/html/openapi:ro
      # Override the default Nginx configuration.
      - ../nginx.conf:/etc/nginx/conf.d/default.conf:ro
Enter fullscreen mode Exit fullscreen mode

Previewing the OAS file

  1. Open the terminal.

  2. Move the current-dir to the location where docker-compose.yml is located.

  3. Create and start the container.

    docker compose up -d
    

    The -d option runs the container in detached mode, allowing the terminal to remain available.

  4. Open the preview page: http://localhost:{host-port}

  5. Check until satisfied.

  6. Close the preview page.

  7. Stop and remove the container.

    docker compose down
    

Preparation for publication

In order to send some GitHub API requests from a terminal.

Personal Access Token

Create a Personal Access Token (Classic).

repo scope is always required.

Declaring some variables

  • <PERSONAL_ACCESS_TOKEN>
    The personal access token we created.

  • <OWNER>
    The account owner of the repository.

  • <REPO>
    The name of the repository.

  • <BRANCH>
    The branch name used to publish.

PERSONAL_ACCESS_TOKEN="<PERSONAL_ACCESS_TOKEN>"
OWNER="<OWNER>"
REPO="<REPO>"
BRANCH="<BRANCH>"
Enter fullscreen mode Exit fullscreen mode

Publishing

Changing repository from private to public

In a free plan account, we cannot publish GitHub Pages from a private repository. Therefore, in this case, we need to update the repository from private 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 '{
    "private": false
  }'
Enter fullscreen mode Exit fullscreen mode

or

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"
  }'
Enter fullscreen mode Exit fullscreen mode

Activating 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\": \"/\"
       }
     }"
Enter fullscreen mode Exit fullscreen mode
  • After GitHub Pages is enabled, the site based on index.html will be built and deployed. We can check the progress of the build by sending the following request.

    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, the 409 conflict error will be returned.

  • Since the BRANCH variable is used to specify the branch, the single quotes in the request body must be changed to double quotes. Assuming BRANCH="main", the differences are as follows:

    BRANCH="main"
    
    curl -L \
      # soft
      -d "{
           \"build_type\": \"legacy\",
           \"source\": {
             \"branch\": \"$BRANCH\",
             \"path\": \"/\"
           }
         }"
      # hard
      -d '{
        "build_type": "legacy",
        "source": {
          "branch": "main",
          "path": "/"
        }
      }'
    
  • The GitHub Pages URL is included in the html_url property of the response.

Retrieving 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"
Enter fullscreen mode Exit fullscreen mode
  • The URL is included in the html_url property of the response.

Unpublishing

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"
Enter fullscreen mode Exit fullscreen mode

Republishing

We just need to send the same request as when activating the site.

Sample Repositories

Remark

This publishing procedure does not depend on the number of OAS files. i.e. even if a OAS file is split into multiple files, we can follow this procedure to publish.

Top comments (0)