🔛

GitHubワークフロー|自動デプロイでビルドすると外部APIとの通信で401エラーが返る(ヘッドレスCMS等)

    ヘッドレスCMS
    Git・GitHub

やりたいこと・現状と前提

やりたいこと

  • GitHubワークフローでNext.jsのビルドとFTPサーバーへのアップロードをしたい
  • mainブランチへのプルリクがクローズするとワークフローが動くように組む

現状

  • プルリクのトリガーとFTPアップは検証済みで.github/workflows/main.ymlの記述に問題はない
  • Next.jsのビルドはローカル上では成功している

前提

前提としてコンテンツ管理をヘッドレスCMSのNewtでしていて、Next.jsで下記のように展開できるように組んでいます。

NewtのAPIにリクエストする関数

import { createClient } from 'newt-client-js'

const client = createClient({
  spaceUid: process.env.NEWT_SPACE_UID + '',
  token: process.env.NEWT_CDN_API_TOKEN + '',
  apiType: 'cdn',
})

export const getArticles = async () => {
  const { items } = await client.getContents<NewtArticle>({
    appUid: process.env.NEWT_APP_UID_TECH_BLOG + '',
    modelUid: process.env.NEWT_APP_UID_TECH_BLOG_ARTICLE + '',
    query: {
      select: ['_id', '_sys', 'slug', 'title', 'pickup', 'issue', 'body', 'thumbnail', 'categorys'],
    },
  })
  return items
}

ブログ詳細を展開するpage.tsx

export async function generateStaticParams() {
  const articles = await getArticles()
  return articles.map( article => (
    {
      slug: article.slug
    }
  ))
}

export default async function BlogDetail({
  params
}: Props) {
  const { slug } = params
  const article = await getArticleBySlug(slug)
  if (!article) return
  return <>
    {/* ブログ一覧を展開するJSX */}
  </>
}

.github/workflows/main.ymlの記述

name: Next.js Build & FTP Upload

on:
  pull_request:
    branches:
      - main
    types: [closed]

  repository_dispatch:
    types: [Newt_Manual_Deploy]

jobs:
  ftp-deploy:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [20.x]

    steps:
      - uses: actions/checkout@v3

      - name: Use Node.js ${{ matrix.node-version }}

        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'yarn'

      - name: Install Dependencies
        run: yarn install

      - name: Build
        run: yarn build

      - name: Sync files
        uses: SamKirkland/FTP-Deploy-Action@4.3.0
        with:
          server: ${{ secrets.FTP_SERVER }}
          username: ${{ secrets.FTP_USERNAME }}
          password: ${{ secrets.FTP_PASSWORD }}
          server-dir: ${{ secrets.FTP_SERVER_DIR }}
          local-dir: ./out/

GitHubワークフローでの401エラーの詳細と原因

上記のmain.yamlのステップInstall dependenciesまでは成功していて、buildのフェーズにて下記の401エラーが返ってきました。

Collecting page data ...
401 Unauthorized: {
  "status": 401,
  "code": "Unauthorized",
  "message": "The authorization token was invalid.",
  "request": {
    "method": "get",
    "headers": {
      "Accept": "application/json, text/plain, */*",
      "Authorization": "***",
      "User-Agent": "axios/1.7.4",
      "Accept-Encoding": "gzip, compress, deflate, br"
    },
    "url": "https://undefined.cdn.newt.so/v1/undefined/undefined?select=_id%2C_sys%2Cslug%2Ctitle%2Cpickup%2Cbody%2Cthumbnail%2Ccategorys"
  }
}

401は認証エラーなので、Newt側で設定したアクセストークンを正しく指定できていない可能性が高いです。

401 Unauthorized|MDN

というかそもそも、requesturlプロパティの値がどう見ても正しくなく、undefinedだらけになっています。

エラーの原因は.env.localファイルを参照できていないから

原因は超シンプルで、Newtとの通信に関わる認証情報はすべて.env.localファイルで管理していて、当然そのファイルは.gitignoreでリモートには上げていないので、GitHubのワークフロー上で参照できないからでした。

.env.localはGitHubの管理下にはおかず、別の方法で参照できるようにすれば解決できます。

【解決策】GitHub Secretsで設定した値を参照してワークフロー中に.env.localを出力する

GithubActionsで.envファイルを作成する方法

上記の記事を参照させていただいて、やり方の候補は3つ。

  • echoコマンドを使う方法
  • Environment Variablesを使う方法
  • secretsを使う方法

色々確認して、GitHub Secretsで環境変数を設定してその値を参照して.env.localファイルを出力するのが、管理のしやすさと実装しやすさ的に楽でした。

実装方法

.github/workflows/main.ymlの記述

... [省略] ...
    steps:
      - uses: actions/checkout@v3

      - name: Use Node.js ${{ matrix.node-version }}

        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'yarn'

      - name: Install Dependencies
        run: yarn install

      - name: Create .env File
        run: |
          echo "${{ secrets.ENV_LOCAL }}" > $GITHUB_WORKSPACE/.env.local

      - name: Build
        run: yarn build

      - name: Sync files
... [省略] ...

新たにCreate .env Fileという記述を追加しています。secretsにGitHub Secretsで設定した変数が格納されており、$GITHUB_WORKSPACEはワークフロー中のプロジェクトルートを指しています。

これでワークフロー上でも、.env.localファイルを参照できるようになります。

GitHub Secretsの設定

GitHubの変数は下記の手順で設定できます。

  • GitHubのリポジトリ画面 > Settings > Secrets and variables
  • New repository secretでプロパティ名と値を設定

これでmain.yamlにて${{ secrets.__[設定したプロパティ]__ }}と書けば参照できるようになります!