Nextjs: API Routes

Nextjs: API Routes

2022.06.09

Nextjsとは

Nextjsを使い始めたばかりはpageディレクトリの直下にファイルを追加すれば自動でルーティングしてくれるReactで書けるやつ。くらいの印象でNextjsのありがたみがよくわかっていませんでしたが、それはnext build && next exportで静的ファイルを作っていただけだったからかもしれません。こうやって作られた静的HTMLファイルはサーバーのどこかにそのままコピーされて、そのサーバーにアクセスしたユーザーにHTMLファイルを送るのはnginxやApacheが担うというのが一連の流れでした。

ですがNextjsの機能はこれだけではありません。Nextjsはサーバーとしての機能も有しており, npm run startで特定のポートにアクセスするとページが現れるのはNextjsの内部でサーバーが動いているからなのです。


API Routesとは

next exportで作成された静的ファイルに含まれるJavaScriptのファイル群は全てブラウザ上で動くコードです。しかしブラウザ上ではできないこともあります。今回私が直面した問題はSendGridのAPIがブラウザから呼び出せないという問題です。これはブラウザにAPI keyが埋め込まれるとそれにアクセスしたユーザーにAPIキーが丸見えになってしまうためです。そのためSendGridのAPIをサーバー上で呼び出す必要があります。こういった場合に使われるのがAPI Routesです。

API Routesはpages/api/に作ります。呼び出す際は/api/ファイル名 でアクセスします。以下がSendGridでAPIを呼び出すサンプルコードです。

undefined
import sgMail from "@sendgrid/mail";
import { NextApiRequest, NextApiResponse } from "next";

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  sgMail.setApiKey(API_KEY as string);
  const msg = {
    from: "[email protected]",
    to: "[email protected]",
    subject: `sample code`,
    text: req.body.message,
  };
  return sgMail
    .send(msg)
    .then(() => {
      res.status(200).end();
    })
    .catch(() => {
      return res.status(500).end();
    });
}

このコードを見てどうしてこんな回りくどい書き方をしているのかと思うかもしれません(return の後)が、async awaitで書くこともできます(たぶん)。ですが後述するVercelでデプロイする場合はこう書く必要があります。

呼び出す側は

undefined
const res = await fetch("/api/file-name", {
        body: JSON.stringify(data),
        headers: {
          "Content-Type": "application/json",
        },
        method: "POST",
      });

とするだけです。


どうデプロイするか

next build && next exportで静的ファイルを作ろうとするとwarningが出ます。前述の通りAPI Routeはサーバー側の処理なのでnext exportで作成されたファイルはAPI Routeの処理を含んでいません。ですがエラーにはならないのでこのwarningを見逃すとapi呼び出しでただエラーが返ってくるだけになってしまいます。next buildで.nextディレクトリにserverディレクトリやchunk/pagesができますがこのserverディレクトリにはAPI Routesのコードが含まれています。どうやってこれらを公開しようかと調べた結果Vercelを使うという結論に至りました。


Vercelとは

Nextjsを開発したVercelが運営するクラウドホスティングサービスです。GitHubのリポジトリを選択するだけで自動的にサイトを公開してくれます。これまでfirewallの設定や証明書の取得をしてきたのが嘘のように一瞬で公開されました。しかも無料で使えるのでおすすめです。


VercelとAPI Routesを使うときの注意点

ここで先程のAPI Routesのコードが回りくどい話に戻ります。VercelでAPI Routesに非同期処理を書くとうまく動かないという状態になりました。正常に動作することもあればエラーが返ってくる場合もある、という一番困るやつです。参考記事は最後に載せていますが、どうやらサーバーが必要最低限で起動、停止を繰り返しているからではないか、と考えられます。この解決方法としてPromiseを返せばよい、ということで先程のようなコードになったのですが、async awaitで書いても同じことをしているような気もしていて、なぜこれで動いているのかあまりわかっていません。


参考文献

nextjsのapi routeをローカルでは問題が出ないのにvercelに置いた途端挙動不明になる場合
初心者でもできるNext.jsのVercelへのデプロイ方法(GitHub経由)