Menu

APIルート

補足: App Routerを使用している場合、APIルートの代わりにサーバーコンポーネントまたはルートハンドラを使用できます。

APIルートは、Next.jsで公開APIを構築するためのソリューションを提供します。

pages/apiフォルダー内のファイルは/api/*にマッピングされ、pageではなくAPIエンドポイントとして扱われます。サーバーサイド専用のバンドルであり、クライアントサイドのバンドルサイズを増やしません。

例えば、次のAPIルートは200のステータスコードを持つJSONレスポンスを返します:

pages/api/hello.ts
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!' })
}
pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}

補足:

パラメータ

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  // ...
}

HTTPメソッド

APIルートで異なるHTTPメソッドを処理するには、リクエストハンドラでreq.methodを使用できます:

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    // POSTリクエストを処理
  } else {
    // 他のHTTPメソッドを処理
  }
}
pages/api/hello.js
export default function handler(req, res) {
  if (req.method === 'POST') {
    // POSTリクエストを処理
  } else {
    // 他のHTTPメソッドを処理
  }
}

リクエストヘルパー

APIルートは、受信リクエスト(req)を解析するための組み込みリクエストヘルパーを提供します:

  • req.cookies - リクエストで送信されたCookieを含むオブジェクト。デフォルトは{}
  • req.query - クエリ文字列を含むオブジェクト。デフォルトは{}
  • req.body - content-typeで解析された本文を含むオブジェクト、または本文が送信されていない場合はnull

カスタム設定

すべてのAPIルートは、デフォルト設定を変更するためのconfigオブジェクトをエクスポートできます:

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '1mb',
    },
  },
  // この関数の最大実行時間を指定します(秒単位)
  maxDuration: 5,
}

bodyParserは自動的に有効になります。本文をStreamまたはraw-bodyで使用する場合は、falseに設定できます。

自動bodyParsingを無効にする1つのユースケースは、例えばGitHubからのwebhookリクエストの生の本文を検証できるようにすることです。

export const config = {
  api: {
    bodyParser: false,
  },
}

bodyParser.sizeLimitは、bytesでサポートされている任意の形式で、解析された本文の最大サイズです:

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '500kb',
    },
  },
}

externalResolverは、このルートが_express_や_connect_などの外部リゾルバによって処理されていることをサーバーに明示的に伝えるフラグです。このオプションを有効にすると、未解決のリクエストに関する警告が無効になります。

export const config = {
  api: {
    externalResolver: true,
  },
}

responseLimitは自動的に有効になり、APIルートのレスポンス本文が4MBを超える場合に警告します。

サーバーレス環境以外でNext.jsを使用しており、CDNや専用メディアホストを使用しない場合の性能への影響を理解している場合は、このリミットをfalseに設定できます。

export const config = {
  api: {
    responseLimit: false,
  },
}

responseLimitは、バイト数またはbytesでサポートされている任意の文字列形式(1000'500kb''3mb'など)を取ることもできます。 この値は、警告が表示される前の最大レスポンスサイズになります。デフォルトは4MB。(上記参照)

export const config = {
  api: {
    responseLimit: '8mb',
  },
}

レスポンスヘルパー

サーバーレスポンスオブジェクト(しばしばresと省略される)には、開発者の体験を向上させ、新しいAPIエンドポイントの作成を高速化するExpress.js風のヘルパーメソッドのセットが含まれます。

含まれるヘルパーは以下の通りです:

  • res.status(code) - ステータスコードを設定する関数。codeは有効なHTTPステータスコードである必要があります
  • res.json(body) - JSONレスポンスを送信します。bodyシリアライズ可能なオブジェクトである必要があります
  • res.send(body) - HTTPレスポンスを送信します。bodystringobject、またはBufferにできます
  • res.redirect([status,] path) - 指定されたパスまたはURLにリダイレクトします。statusは有効なHTTPステータスコードである必要があります。指定されていない場合、statusはデフォルトで「307」「一時的リダイレクト」になります。
  • res.revalidate(urlPath) - getStaticPropsを使用してオンデマンドでページを再検証しますurlPathstringである必要があります。

レスポンスのステータスコードの設定

クライアントに応答を返す際に、応答のステータスコードを設定できます。

次の例では、レスポンスのステータスコードを200OK)に設定し、Hello from Next.js!の値を持つmessageプロパティをJSONレスポンスとして返します:

pages/api/hello.ts
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!' })
}
pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}

JSONレスポンスの送信

クライアントに応答を送信する際、JSONレスポンスを送信できます。これはシリアライズ可能なオブジェクトである必要があります。 実際のアプリケーションでは、リクエストされたエンドポイントの結果に応じて、クライアントにリクエストの状態を知らせたいことがあるでしょう。

次の例は、ステータスコード200OK)と非同期操作の結果を含むJSONレスポンスを送信します。発生する可能性のあるエラーを処理するために、try-catchブロックに含まれており、適切なステータスコードとエラーメッセージがキャッチされ、クライアントに送り返されます:

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const result = await someAsyncOperation()
    res.status(200).json({ result })
  } catch (err) {
    res.status(500).json({ error: 'failed to load data' })
  }
}
pages/api/hello.js
export default async function handler(req, res) {
  try {
    const result = await someAsyncOperation()
    res.status(200).json({ result })
  } catch (err) {
    res.status(500).json({ error: 'failed to load data' })
  }
}

HTTPレスポンスの送信

HTTPレスポンスの送信は、JSONレスポンスを送信する場合と同じ方法で動作します。唯一の違いは、レスポンスボディがstringobject、またはBufferになることができる点です。

次の例は、ステータスコード200OK)と非同期操作の結果を含むHTTPレスポンスを送信します。

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const result = await someAsyncOperation()
    res.status(200).send({ result })
  } catch (err) {
    res.status(500).send({ error: 'failed to fetch data' })
  }
}
pages/api/hello.js
export default async function handler(req, res) {
  try {
    const result = await someAsyncOperation()
    res.status(200).send({ result })
  } catch (err) {
    res.status(500).send({ error: 'failed to fetch data' })
  }
}

指定されたパスまたはURLへのリダイレクト

フォームを例に挙げると、フォームを送信した後にクライアントを特定のパスまたはURLにリダイレクトしたい場合があります。

次の例は、フォームが正常に送信された場合、クライアントを/パスにリダイレクトします:

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const { name, message } = req.body
 
  try {
    await handleFormInputAsync({ name, message })
    res.redirect(307, '/')
  } catch (err) {
    res.status(500).send({ error: 'Failed to fetch data' })
  }
}
pages/api/hello.js
export default async function handler(req, res) {
  const { name, message } = req.body
 
  try {
    await handleFormInputAsync({ name, message })
    res.redirect(307, '/')
  } catch (err) {
    res.status(500).send({ error: 'failed to fetch data' })
  }
}

TypeScriptの型の追加

nextからNextApiRequestNextApiResponseの型をインポートすることで、API Routesをより型安全にすることができます。さらに、レスポンスデータの型も指定できます:

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の本文はanyになります。これは、クライアントが任意のペイロードを含む可能性があるためです。使用する前に、ボディの型/構造を実行時に検証する必要があります。

ダイナミックAPI Routes

API Routesはダイナミックルートをサポートしており、pages/で使用されるファイル名付けルールに従います。

pages/api/post/[pid].ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const { pid } = req.query
  res.end(`Post: ${pid}`)
}
pages/api/post/[pid].js
export default function handler(req, res) {
  const { pid } = req.query
  res.end(`Post: ${pid}`)
}

これで、/api/post/abcへのリクエストは、テキストPost: abcで応答します。

すべてをキャッチするAPI routes

三点リーダー(...)をブラケット内に追加することで、API Routesですべてのパスをキャッチするように拡張できます。例えば:

  • pages/api/post/[...slug].js/api/post/aにマッチし、/api/post/a/b/api/post/a/b/cなどにもマッチします。

補足: slug以外の名前を使用できます。例:[...param]

マッチしたパラメータはクエリパラメータ(例のslug)としてページに送信され、常に配列になります。したがって、/api/post/aのパスは次のクエリオブジェクトを持ちます:

{ "slug": ["a"] }

/api/post/a/bと他のマッチするパスの場合、新しいパラメータが配列に追加されます:

{ "slug": ["a", "b"] }

例:

pages/api/post/[...slug].ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const { slug } = req.query
  res.end(`Post: ${slug.join(', ')}`)
}
pages/api/post/[...slug].js
export default function handler(req, res) {
  const { slug } = req.query
  res.end(`Post: ${slug.join(', ')}`)
}

これで、/api/post/a/b/cへのリクエストは、テキストPost: a, b, cで応答します。

オプションのすべてをキャッチするAPI routes

三点リーダーをダブルブラケット([[...slug]])に入れることで、キャッチオールルートをオプションにできます。

例えば、pages/api/post/[[...slug]].js/api/post/api/post/a/api/post/a/bなどにマッチします。

キャッチオールとオプションキャッチオールルートの主な違いは、オプションの場合、パラメータのないルート(上記の例では/api/post)もマッチする点です。

クエリオブジェクトは次のようになります:

{ } // GET `/api/post` (空のオブジェクト)
{ "slug": ["a"] } // `GET /api/post/a` (単一要素の配列)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (複数要素の配列)

注意点

  • 事前定義されたAPI routesは、ダイナミックAPI routesよりも優先され、ダイナミックAPI routesはキャッチオールAPI routesよりも優先されます。以下の例を参照してください:
    • pages/api/post/create.js - /api/post/createにマッチします
    • pages/api/post/[pid].js - /api/post/1/api/post/abcなどにマッチしますが、/api/post/createにはマッチしません
    • pages/api/post/[...slug].js - /api/post/1/2/api/post/a/b/cなどにマッチしますが、/api/post/create/api/post/abcにはマッチしません

Edge API Routes

Edge RuntimeでAPI Routesを使用したい場合は、App Routerに段階的に移行し、代わりにRoute Handlersを使用することをお勧めします。

Route Handlersの関数シグネチャは同型的であり、Edge と Node.js の両方のランタイムで同じ関数を使用できます。