TL;DR
この記事では、Next.js と TypeScript を活用し、API ルートの制作とその適用方法について詳しく説明します。API ルートは Next.js アプリケーションの一部で、エンドポイントとして機能します。ここでは、その作成方法と、クライアント側での使用方法を実例を通じて見ていきます。
開発環境 | バージョン |
---|---|
Next.js | 13.4.4 |
TypeScript | 5.0.4 |
Emotion | 11.11.0 |
React | 18.2.0 |
API ルートとは?
そもそも、API ルートとは、何なのか?ということですが、例えば、みなさんがお店で何かを買うとき、まず商品を選んで、レジに持って行き、お金を払って商品をもらいますよね。そのとき、お店の人が何をすべきかを知るために、レジがあるところに行くわけです。この「レジがあるところ」が、API ルートという考え方に似ています。
API ルートは、ウェブサイトやアプリが他のプログラムと「話す」ための特別な場所です。まるでレジのように、何かを要求したり、情報を得たりするための場所と言えます。例えば、あるアプリが天気の情報を必要とするとき、そのアプリは「天気情報の API ルート」に行って、天気の情報を尋ねます。
API ルートは、ウェブサイトやアプリが特定の情報を要求したとき、または何か特定のことをするように要求したときに、どのように応答するかを定義します。API ルートを通じて、ウェブサイトやアプリは他のプログラムやサービスと「会話」をすることができます。
例えば、私たちが天気予報アプリで今日の天気を調べるとき、天気予報アプリは「天気の API ルート」に行って「今日の天気は何ですか?」と尋ね、API ルートは「今日の天気は晴れです」と答えます。このように、API ルートはプログラム同士の会話を可能にしてくれるのです。
Next.js の API ルート
API ルートは、Next.js に内蔵されたサーバーレス関数です。これらの関数は、pages/api
ディレクトリ内の .ts
ファイルとして配置され、そのファイルパスがエンドポイントの URL となります。このエンドポイントを通じて、データの取得やデータの更新など、クライアントからのリクエストに対応することができます。
わかりやすいように、シンプルなコードで解説します。
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}
このコードは、Next.js で API ルートを作成するためのサンプルコードです。
handler のところは、API ルートを定義するための関数(handler)を宣言しています。Next.js はこのような形式の関数を API ルートとして認識します。
関数handler
は 2 つの引数を取ります。
req
(request)
これは API ルートへのリクエスト情報を含むオブジェクトで、リクエストに含まれるデータやリクエストの種類(GET、POST など)などを管理します。
res
(response)
これはレスポンスを構築するためのオブジェクトで、API ルートからのレスポンスを送る際に用いられます。
res.status(200).json({ name: 'John Doe' })
この行はレスポンスオブジェクト(res
)を使って、クライアント(API ルートへのリクエストを行ったエンティティ)にレスポンスを送ります。
res.status(200)
は、 HTTP ステータスコード 200 をレスポンスに設定しています。HTTP ステータスコード 200 は、「成功」を意味します。
.json({ name: 'John Doe' })
は、レスポンスの内容を JSON 形式で送ります。この例では、{ name: 'John Doe' }
という JSON を送っています。これは、"name"というキーの値として"John Doe"という文字列を持つ JavaScript のオブジェクトを、JSON として送信します。
最後に、関数の宣言を終了します。
以上のように、この API ルートはリクエストを受けると、必ずステータスコード 200 とともに、{ name: 'John Doe' }
という JSON 形式のデータを返します。
この形式では、関数が直接エクスポートされているため、別の名前でインポートすることはできません(常に handler
として扱われます)。
他にも、シンプルな API ルートを作成しましょう。以下のファイルは pages/api/hello.ts
として保存します。
import { NextApiRequest, NextApiResponse } from 'next'
const handler = (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).json({ text: 'Hello' })
}
export default handler
このコードでは、handler
関数が API ルートを定義しています。この関数は、リクエストオブジェクト (req
) とレスポンスオブジェクト (res
) を引数に取り、レスポンスのステータスコードを 200
に設定し、レスポンスのボディに JSON を含めます。
処理を分岐させる
次のコードは、API ルートにおいてリクエストの HTTP メソッド(GET、POST、PUT など)によって処理を分岐させている例です。
export default function handler(req, res) {
if (req.method === 'POST') {
// Process a POST request
} else {
// Handle any other HTTP method
}
}
1 行目は、API ルートをハンドリングする関数を宣言しています。関数handler
は引数としてリクエストオブジェクトreq
とレスポンスオブジェクトres
を受け取ります。
2 行目では、リクエストオブジェクトのmethod
プロパティを参照し、その値がPOST
であるかどうかを評価しています。HTTP メソッドがPOST
であれば、このif
ブロック内のコードが実行されます。ここでは「// Process a POST request」のコメントが書かれていますが、実際には POST リクエストを処理する具体的なコードがこの位置に書かれることを期待しています。
逆に、HTTP メソッドがPOST
でなければ、4 行目のelse
ブロック内のコードが実行されます。この部分では、POST 以外のリクエストメソッド(GET、PUT、DELETE など)を処理するコードが記述されます。
以上のように、この関数は API ルートに送られてきたリクエストの HTTP メソッドによって、適切な処理を行います。これにより、一つの API ルートで複数の HTTP メソッドをハンドリングすることが可能となります。
API ルートの実装
それでは、もっと複雑な例を見てみましょう。ユーザー情報を取得する API ルートを作成してみます。新しい API ルートは pages/api/user.ts
というパスに保存します。
import { NextApiRequest, NextApiResponse } from 'next'
type User = {
name: string
email: string
}
const handler = (req: NextApiRequest, res: NextApiResponse<User>) => {
if (req.method === 'GET') {
// ユーザー情報の偽装
const user: User = {
name: 'John Doe',
email: 'john.doe@example.com',
}
res.status(200).json(user)
} else {
res.setHeader('Allow', ['GET'])
res.status(405).end(`Method ${req.method} Not Allowed`)
}
}
export default handler
ここで、User
型を定義し、それを NextApiResponse
の型引数として使っています。これにより、この API ルートがユーザー情報を返すことを明示的に示しています。また、この API ルートは GET リクエストのみを許可し、それ以外のメソッドのリクエストに対しては 405 ステータスコードを返します。