🚀

【Next.js和訳】API Routes/API Middlewares

4 min read

この記事について

株式会社 UnReact はプロジェクトの一環としてNext.js ドキュメントの和訳を行っています。

この記事は、API Routes/API Middlewaresの記事を和訳したものです。

記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。

API Middlewares

APIルートには、入力されたリクエスト(req)を解析するミドルウェアが組み込まれています。それらのミドルウェアは

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

コンフィグのカスタム

すべてのAPIルートは、デフォルトの設定を変更するために、configオブジェクトをエクスポートすることができ、その内容は次のとおりです。

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '1mb',
    },
  },
}

apiオブジェクトは、APIルートで利用可能なすべての設定を含みます。

bodyParserボディの解析を有効にします。Streamとして消費したい場合は無効にすることができます。

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

bodyParser.sizeLimitは、解析されたボディに許容される最大サイズで、バイトでサポートされる任意のフォーマットで、以下のようになります。

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

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

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

Connect/Express対応ミドルウェア

Connect互換のミドルウェアを使用することもできます。

例えば、APIのエンドポイントにCORSを設定するには、corsパッケージを活用します。

まず、corsをインストールします。

npm i cors
# or
yarn add cors

それでは、APIルートにcorsを追加してみましょう。

import Cors from 'cors'

// corsミドルウェアの初期化
const cors = Cors({
  methods: ['GET', 'HEAD'],
})

// ミドルウェアが実行されるのを待ってから続行するヘルパーメソッド
// また、ミドルウェアでエラーが発生したときにエラーを出す
function runMiddleware(req, res, fn) {
  return new Promise((resolve, reject) => {
    fn(req, res, (result) => {
      if (result instanceof Error) {
        return reject(result)
      }

      return resolve(result)
    })
  })
}

async function handler(req, res) {
  // ミドルウェアの実行
  await runMiddleware(req, res, cors)

  // 残りのAPIロジック
  res.json({ message: 'Hello Everyone!' })
}

export default handler

完成したアプリを見るには、API Routes with CORSの例にアクセスしてください。

TypeScriptによるreq/resオブジェクトの拡張

type-safetyをよくするために、reqresのオブジェクトを拡張することはお勧めしません。代わりに、関数を使ってこれらを操作します。

utils/cookies.ts
import { serialize, CookieSerializeOptions } from 'cookie'
import { NextApiResponse } from 'next'

/**
 * これは、`res`オブジェクトを使用して`cookie`を設定します。
 */

export const setCookie = (
  res: NextApiResponse,
  name: string,
  value: unknown,
  options: CookieSerializeOptions = {}
) => {
  const stringValue =
    typeof value === 'object' ? 'j:' + JSON.stringify(value) : String(value)

  if ('maxAge' in options) {
    options.expires = new Date(Date.now() + options.maxAge)
    options.maxAge /= 1000
  }

  res.setHeader('Set-Cookie', serialize(name, String(stringValue), options))
}
pages/api/cookies.ts
import { NextApiRequest, NextApiResponse } from 'next'
import { setCookie } from '../../utils/cookies'

const handler = (req: NextApiRequest, res: NextApiResponse) => {
  // `res`オブジェクトを使って純粋な関数を呼び出すと、`set-cookie`ヘッダーが追加されます。
  setCookie(res, 'Next.js', 'api-middleware!')
  // `set-cookie`ヘッダーを返すので、それをブラウザで表示して、動作することを示すことができます。
  res.end(res.getHeader('Set-Cookie'))
}

export default handler

これらのオブジェクトが拡張されるのを避けられない場合は、追加のプロパティを含む独自のタイプを作成する必要があります。

pages/api/foo.ts
import { NextApiRequest, NextApiResponse } from 'next'
import { withFoo } from 'external-lib-foo'

type NextApiRequestWithFoo = NextApiRequest & {
  foo: (bar: string) => void
}

const handler = (req: NextApiRequestWithFoo, res: NextApiResponse) => {
  req.foo('bar') // これで `req.foo` をタイプエラーなしで使えるようになりました。
  res.end('ok')
}

export default withFoo(handler)

withFoo()をエクスポートから削除してもコードはコンパイルされてしまうので、これは安全ではないことに注意してください。

Discussion

ログインするとコメントできます