はじめに
こんにちは、Gakken LEAPのフロントエンドエンジニアの Okuma です。
今回はNext.jsにおけるAPI Routes、Route Handlers、Server Components、Server Actionsの違いについてまとめてみようと思います。
それぞれの用語の主な違いと、さらにNextのリクエストとレスポンスについてもいくつか説明できればと思います。
Next.jsやReact関連のライブラリやコンポーネントのドキュメントや記事を読んでいると、よくこの4つのキーワードを見かけると思います。どれもNext.jsで利用できる機能なんだなくらいで思っていましたが、決定的な違いについてはちゃんと把握していませんでした。
簡単に要約すると以下になります。
- API Routes:Page RouterでパブリックAPIを公開するために使用する
- Route Handlers: App RouterでパブリックAPIを公開するために使用する
- Server Components: App Routerでサーバー側のUIをレンダリングするために使用する
- Server Actions: App Routerでデータを取得したり、フォーム送信を処理したいするために使用する
API Routes
API RoutesはPage Routerの一部であり、パブリックAPI(外部のアプリケーションなどがアクセスできるようにするエンドポイント)を構築するする場合にのみ使用します。
API Routesを作成するには、pages/api
フォルダの下にファイルを配置します。
import type { NextApiRequest, NextApiResponse } from 'next'
type ResponseData = {
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
コードを見ると、NextApiRequest
とNextApiResponse
がここでは使用されていますが、NextRequest
とNextResponse
も存在します。このあたりがNext.jsのドキュメントのわかりにくさを表しています。
より詳しくすると、
-
NextApiRequest
とNextApiResponse
はグローバルな「next」パッケージの一部であり、API Routesを型安全にするのに適しています。また、Request HelperとResponse Helperと呼ばれる追加のヘルパーメソッドを提供することで、Node.jsから直接ServerResponseを拡張できます。これはPages Routerで使用されていた方法になります。 - NextRequestとNextResponseは「next/server」パッケージの一部で、大きな違いはResponse APIを直接拡張できることです。この2つはPages Router(API Routes)とApp Router(Route Handlers)の両方で使うことができ、同じ振る舞いを異なる方法で行います。
ここまでをまとめると、API Routes(Pages Router)の場合はNextApiRequest
とNextApiResponse
を使用し、Route Handlers(App Router)の場合はNextRequest
とNextResponse
を使用します。
Route Handlers
Route HandlersはApp Routerでのみ使用することができ、API Routesから完全に置き換えることができます。
app/api
ディレクトリ内のroute.t(j)s
ファイルで定義し、page.t(j)sx
ファイルと同じフォルダや階層に配置することはできません。
API Routesとの大きな違いは、ハンドラー関数を使用する代わりに、GET
、POST
、PUT
、PATCH
、DELETE
などのHTTPメソッドを直接記述して定義することができることです。
実際に例を見てみましょう。
import { cookies } from 'next/headers'
export async function GET(request: Request) {
const cookieStore = await cookies()
const token = cookieStore.get('token')
return new Response('Hello, Next.js!', {
status: 200,
headers: { 'Set-Cookie': `token=${token.value}` },
})
}
Server Components
Server ComponentsはRoute HandlersとともにApp Routerに導入されたもう一つの追加機能です。デフォルトでは、ファイルの先頭に'use client'
ディレクティブを追加しない限り、Next.jsでは全てのコンポーネントはSever Componentsになります。
Server Componentsは、その名前の通り、サーバー上で直接処理(特にUIのレンダリングなど)を実行でき、様々な利点があります。データを取得する場合は、後述のServer Actionsを使用して実行します。UIレンダリングとアクションの両方がサーバー上で実行されるため、パフォーマンスが大幅に向上します。
Next.jsのドキュメントでは、Server Componentsは他のコンポーネントと同じように動作するため、具体的な例はあまり提供されていません。唯一制限されていることは、ユーザーのインタラクションがクライアント側で行われなければいけないということです。
Client ComponentsをServer Componentsの子として持つことができるので、Server Componentsでデータを取得し、Client Componentsにそれを渡してインタラクションをさせる構成で実装することができることも頭に入れておくと良いかもしれません。
Server Actions
独自のaction.ts
ファイルで宣言されるServer Actionsは、データを取得したり、フォームの送信を処理したりするために使用される非同期関数です。
通常はServer Componentsから呼び出す方が便利ですが(全てサーバー側で維持)、ユーザーの操作が必要な場合はClient Componentsから呼び出すこともできます。
ファイル内すべての関数をServer Actionsとして有効にするには、ファイルの先頭にuse server
ディレクティブを明示的に設定し、すべての関数をasync
として宣言する必要があります。
または、特定の関数のみをServer Actionsとして宣言することもできます。このような場合は、use server
を直接関数内に記述します。
async function addToCart(data) {
"use server";
// Rest of the function here
}
このアプローチにより、Server Components内でServer Actionsを使用できます。ただし、Client ComponentsにServer Actionsを含めるためには、上記の別のaction.ts
ファイルからインポートすることが唯一の方法です。
おわりに
ここまでで、ReactとNext.jsに関する混乱しやすい用語が幾分かは明確になっていれば幸いです。
フロントエンドエンジニアとしてこれらを状況によって適切に使い分けられるようになりたいと思います。
エンジニア募集中
Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています!!
ぜひお気軽にカジュアル面談へお越しください!!