API機能
Next.jsには簡易なAPI機能が存在してます。
一件フロントエンドの検証・素振りには必要なさそうに見えますが、CORSの回避などにとても便利に利用できます。
例として今回はnager.dateの祝日データを利用してみます。
// pages/index.tsx
// (動かない例)
import { useEffect, useState } from "react"
export default function Home() {
const [holidays, setHolidays] = useState([])
useEffect(() => {
fetch("https://date.nager.at/api/v2/PublicHolidays/2020/JP")
.then(r => r.json())
.then(data => {
setHolidays(data)
})
}, [])
return (
<div>
{holidays.map(day => <div key={day.name}>{day.localName}</div>)}
</div>
)
}
このようにするとおそらくCORSが設定されてないAPIのため下記のようなエラーが出るでしょう
Access to fetch at 'https://date.nager.at/api/v2/PublicHolidays/2020/JP' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
APIを使って解決する
ではこれをAPIを作成することで回避してみましょうpages/api/holidays.ts
として作成してみます。
// /pages/api/holidays.ts
import fetch from 'node-fetch'
export default (req, res) => {
res.statusCode = 200
fetch("https://date.nager.at/api/v2/PublicHolidays/2020/JP")
.then(r => r.json())
.then(data => res.json(data))
}
// pages/index.tsx
// (動く例)
import { useEffect, useState } from "react"
export default function Home() {
const [holidays, setHolidays] = useState([])
useEffect(() => {
fetch("/api/holidays") // ここをProxyしたAPIにする
.then(r => r.json())
.then(data => {
setHolidays(data)
})
}, [])
return (
<div>
{holidays.map(day => <div key={day.name}>{day.localName}</div>)}
</div>
)
}
今度は無事に表示されました。
このようにAPIを利用してProxyすればドメインを経由するため、CORSも問題ありません。またAPIキーを利用するような場合もクライアントに処理させず、API側にキーを隠蔽することもできます。
Tips: ServerSideでCORSを回避する
ちなみに、CORSを回避する方法としてgetServerSideProps
を利用する方法もあります。
import { GetServerSideProps } from "next"
// レンダリング前に実行される
export const getServerSideProps: GetServerSideProps = async () => {
const holidays = await fetch("https://date.nager.at/api/v2/PublicHolidays/2020/JP")
.then(r => r.json())
return { props: { holidays } }
}
export default function Home({ holidays }) {
return (
<div>
{holidays.map(day => <div key={day.name}>{day.localName}</div>)}
</div>
)
}