JavaScript

Next.jsのgetStaticPropsで外部APIからデータを取得する方法

「Next.jsのチュートリアルやってみた」
「ローカルの.mdファイルからデータは取得できる」
「外部APIからデータを取得して表示できん」

こんな状態の方のための記事です。

この記事で解説すること
  • getStaticPropsを使って外部APIのデータをSSGする方法
  • fetchメソッドで外部APIからデータを取得する方法

Next.jsで外部APIからデータを取得する前提

Next.jsのチュートリアルを順当に進めて、以下のチャプターまで辿り着いていることが前提です。

https://nextjs.org/learn/basics/dynamic-routes/dynamic-routes-details

Dynamic Routesによって動的なURLでローカルのマークダウンファイルをparseした投稿ページを表示できている状態ですね。

この時点ではローカルのファイルからデータを取得していますが、今回は外部APIから取得したデータを表示します。

あくまで「外部APIからデータを取得する」ことにフォーカスしたいので、表示するデータはマークダウンとしたいと思います。

少しまわりくどいですが、チュートリアル内で作成したプロジェクトをGitHubにpushして、GitHubのAPIを叩いてマークダウンファイルを取得します。

APIでデータを取得するためのパッケージを導入

getStaticPropsやgetStaticPathsは「サーバーサイド」の処理になります。

通常、フロントからAPIを叩く場合はfetchメソッドを使いますが、サーバーサイドでは”node-fetch”というパッケージのインストールが必要です。

また、GitHubのAPIで取得できるデータのうち、ファイルの中身はエンコードされています。

デコードするために”js-base64″というパッケージも合わせてインストールしましょう。

$ npm install --save node-fetch js-base64

GitHub APIを叩いてファイル名を取得しよう

まずはチュートリアル内でも使われているgetAllPostIds()関数を変更していきます。

getAllPostIds()を修正してGitHubレポジトリからファイルの一覧を取得しよう

lib/posts.js

// 中略
import fetch from 'node-fetch'
// 中略

export async function getAllPostIds() {
    // const fileNames = fs.readdirSync(postsDirectory)

    const repoUrl = "https://api.github.com/repos/deatiger/next-tutorial-torasemi/contents/posts"
    const response = await fetch(repoUrl)
    const files = await response.json()
    const fileNames = files.map(file => file.name)

    // Returns an array that looks like this:
    // [
    //   {
    //     params: {
    //       id: 'ssg-ssr'
    //     }
    //   },
    //   {
    //     params: {
    //       id: 'pre-rendering'
    //     }
    //   }
    // ]
    return fileNames.map(fileName => {
        return {
            params: {
                id: fileName.replace(/\.md$/, '')
            }
        }
    })
}

 

処理の流れ
  1. 対象レポジトリのpostsディレクトリ内の情報を取得するURIを宣言
  2. fetchメソッドでAPIにGETメソッドを送信
  3. responseをjson()で読み取る
  4. ファイル名を取得する

ポイントは、fetchメソッドが非同期処理なので関数にasyncを付与した点です。

fetchメソッドやjson()メソッドを使う際はawaitをつけて実行しましょう。

 

次にgetPostData()を変更します。

getPostData()を修正してGitHubレポジトリからファイル情報を取得しよう

同じくlib/posts.jsを修正します。

lib/posts.js

// 中略
const base64 = require('js-base64').Base64;
// 中略

export async function getPostData(id) {
    const repoUrl = `https://api.github.com/repos/deatiger/next-tutorial-torasemi/contents/posts/${id}.md`
    const response = await fetch(repoUrl)
    const file = await response.json()

    const fileContents = base64.decode(file.content)

    // const fullPath = path.join(postsDirectory, `${id}.md`)
    // const fileContents = fs.readFileSync(fullPath, 'utf8')

    // Use gray-matter to parse the post metadata section
    const matterResult = matter(fileContents)

    // Use remark to convert markdown into HTML string
    const processedContent = await remark()
      .use(html)
      .process(matterResult.content)
    const contentHtml = processedContent.toString()

    // Combine the data with the id and contentHtml
    return {
        id,
        contentHtml,
        ...matterResult.data
    }
}

 

先ほどのgetAllPostIds()と似たような処理ですね。

唯一違う点として、file.contentにbase64のdecode()メソッドを使っています。

前述の通り、GitHubのAPIで取得したファイルの中身(content)はエンコードされてしまっているからです。

さて、残りは以下のファイルを変更します。

pages/posts/[id].js

export async function getStaticPaths() {  // asyncを付与
  const paths = await getAllPostIds()  // awaitで呼び出し
  return {
    paths,
    fallback: false
  }
}

export async function getStaticProps({ params }) {  // asyncを付与
  const postData = await getPostData(params.id)  // awaitで呼び出し
  return {
    props: {
      postData
    }
  }
}

 

これでGitHubのレポジトリ上にあるマークダウンファイルからデータを取得できたはずです。

ABOUT ME
稲垣 貴映
サーバーエンジニア兼Webフロントエンジニア。 新卒で独立系SIerに入社後、金融系システム基盤の構築・運用を3年間経験。 プログラミングを独学していた頃に、CEOの馬谷が開講していたSwiftスクールに通い、2019年9月に入社。 趣味はブラジル音楽の演奏。

COMMENT

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA