「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$/, '')
}
}
})
}
- 対象レポジトリのpostsディレクトリ内の情報を取得するURIを宣言
- fetchメソッドでAPIにGETメソッドを送信
- responseをjson()で読み取る
- ファイル名を取得する
ポイントは、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のレポジトリ上にあるマークダウンファイルからデータを取得できたはずです。
- 無料・簡単・片手でホームページを作成できる自社サービス Rakwi
- Web制作とアプリ開発を学べるオンラインプログラミング講座 Upstairs
- 開発,DX推進支援サービス スタートアッププラン