Closed1

Next/API Routeでhelper関数を使って便利にする

hanetsukihanetsuki

エラーをグローバルに扱いたい

helpers/api.ts
import Cors from 'cors'
import { NextApiRequest, NextApiResponse } from 'next'

const errorHandler = (err: Error|string, res: NextApiResponse) => {
  if (typeof (err) === 'string') {
    // custom application error
    const is404 = err.toLowerCase().endsWith('not found')
    const statusCode = is404 ? 404 : 400
    return res.status(statusCode).json({ message: err })
  }

  // default to 500 server error
  console.error(err)
  return res.status(500).json({ message: err.message })
}

type Handler = {
  [key: string]: (req: NextApiRequest, res: NextApiResponse) => Promise<void>|void
}

const initMiddleware = (middleware: ReturnType<typeof Cors>) => {
  return (req: NextApiRequest, res: NextApiResponse) =>
    new Promise((resolve, reject) => {
      middleware(req, res, (result: unknown) => {
        if (result instanceof Error) {
          return reject(result)
        }
        return resolve(result)
      })
    })
}

const apiHandler = (handler: Handler) => {
  const corsHandler = initMiddleware(
    Cors({
      methods: [...Object.keys(handler).map(k => k.toLowerCase()), 'OPTIONS']
    })
  )
  return async(req: NextApiRequest, res: NextApiResponse) => {
    const method = req.method?.toLowerCase() || ''

    // check handler supports HTTP method
    if (!handler[method]) {
      return res.status(405).end(`Method ${req.method} Not Allowed`)
    }

    try {
      // cors handler
      await corsHandler(req, res)

      // route handler
      await handler[method](req, res)
    } catch (err) {
      if (err instanceof Error || typeof err === 'string') {
        // global error handler
        errorHandler(err, res)
      }
      throw err
    }
  }
}

export { apiHandler }
pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { apiHandler } from 'helpers/api';

export default apiHandler({
    get: getExampleErrors
});

function getExampleErrors(
  req: NextApiRequest,
  res: NextApiResponse
) {
    // ステータスコード 400 で返却する
    throw 'Username or password is incorrect';

    // 文末に'Not Found'を記載しているため、ステータスコード 404 で返却する
    throw 'User Not Found';

    // 正しいレスポンスを返す
    res.status(200).json({ name: 'Jon' })
}

参考:https://jasonwatmore.com/post/2021/08/23/next-js-api-global-error-handler-example-tutorial

このスクラップは2022/01/12にクローズされました