Netlify Functions のパス変更方法は?リクエストボディってどう取るの?など調べた

最近 Cloudflare Pages Workers ばかり触っていて、久々に Netlify Functions に戻ってきたらバージョンが上がっていてワケワカメだったので、調べたことをメモしておく。

目次

とりあえず Netlify CLI をグローバルインストールしておくと楽

まずはとりあえず Netlify CLI をグローバルインストールしておき、ログイン連携をしておく。

$ npm install -g netlify-cli

$ netlify login

Vite 製プロジェクト向けの開発用コマンドを整理する

Vite で作ったプロジェクトで、Netlify Functions などを有効にする開発環境を構築するには、以下のようにする。

  1. $ npm run devvite による開発サーバを起動できるようにしておく
  2. $ netlify dev コマンドで $ npm run dev コマンドを参照するよう、netlify.toml に定義を書いておく
  3. $ netlify dev コマンドで開発用サーバを起動する

$ netlify dev コマンドは専用のポートで開発用サーバを立ち上げるのだが、内部的には $ npm run dev で立ち上げた Vite の開発用サーバにプロキシしていて、Netlify Functions へのアクセスなどだけ自前で調整してくれるような挙動をしている。Vite サーバをラップして Netlify CLI サーバが立ち上がる、というワケだ。

そんなワケで、必要なモジュール類、スクリプトの定義はこんな感じ。開発用サーバを立ち上げる時、ユーザは $ npm run dev の方ではなく $ npm run local-dev の方を叩くが、Netlify CLI 的が内部で $ npm run dev を叩くので両方の定義が package.json に必要、となるワケだ。

{
  "name": "example",
  "private": true,
  "type": "module",
  "scripts": {
    "build": "tsc && vite build",
    "serve": "netlify serve",
    
    "dev"      : "vite --host",
    "local-dev": "netlify dev",
    
    "netlify": "netlify"
  },
  "dependencies": {
    "@netlify/functions": "2.8.1"
  },
  "devDependencies": {
    "@types/node": "22.7.0",
    "netlify-cli": "17.36.2",
    "typescript": "5.6.2",
    "vite": "5.4.7"
  }
}
[build]
  command = "npm run build"
  publish = "dist"
  functions = "api"

[[redirects]]
  from = "/api/*"
  to = "/.netlify/functions/:splat"
  status = 200

[dev]
  command = "npm run dev"

[dev] セクションで、npm run dev を内部的に実行し、そこで立ち上がった開発用サーバのポートを自動的に捕まえてプロキシしているようだ。賢い。

Vite でビルドした資材を本番相当のプレビュー環境として起動したい

前述の package.json に書いたとおり、$ npm run build では tsc による TypeScript のチェックと vite build によるビルドを行っている。

こうしてビルドした静的な資材をプレビューしたい時、Netlify Functions も一緒にプレビュー環境に立ち上げる方法がある。

$ netlify serve コマンドを叩くと、netlify.toml に書いた定義に沿って、$ npm run build が実行され、その資材を利用してプレビュー用サーバが立ち上がる。つまり参照しているのは ./src/ の方ではなく ./dist/ の方になり、ついでに Netlify Functions も動作するプレビューサーバが立ち上がっている状態になる。

Netlify Functions にアクセスするパスを変更したい

Netlify Functions のデフォルトの API エンドポイントパスは /.netlify/functions/【ファイル名】 という形になる。

実際のファイルは、プロジェクト配下の ./netlify/functions/【ファイル名】.ts といった形で置いておけば対応付けされる。

…はて、netlify/ ディレクトリに置くのに、API エンドポイントは /.netlify になるのか…。キモチワルイ…。

できれば Cloudflare Pages Workers のように、/api が API エンドポイントになると分かりやすいので、そのように直す。

前述の netlify.toml にこの設定が既に書かれている。

というワケで、Netlify Functions の資材は ./api/hello.ts のように配置すれば良くなり、フロントエンドから Netlify Functions にアクセスする際のエンドポイントは次のように /api/hello となる。

fetch('/api/hello')
  .then(response => response.json())
  .then(json => { /* Do Something */ });

Netlify Functions で POST リクエストの Body を受け取りたい

Netlify Functions は AWS Lambda 互換の書き方 (exports.handler = (event, context) => {};) も出来るのだが、今回は package.json にて "type": "module" を指定していることもあり、exports. が使えない。

というかそもそも ES Modules 互換の Netlify Functions の書き方が分からないので調べ直したところ、次のように書くらしい。

import { Context } from '@netlify/functions';

export default async (request: Request, context: Context) => {
  return new Response(JSON.stringify({ message: 'Hello World' }), { status: 200 });
}

Request と Response は特にインポート不要。Deno とかと同じ、Web 標準というヤツみたい。


Netlify Functions は API の呼び出されるメソッドを限定しないため、/api/helloGET でも POST でも実行できてしまう。

このメソッド判定は if(request.method === 'POST') などのように if 文でチェックが可能。POST しか受け付けたくない API の場合は、このように request.method をチェックして HTTP 405 あたりを返しておくと良いだろう。


そんで、POST リクエストだった場合はリクエストボディってどうやって取得するの?ということなのだが、答えはこう。

import { Context } from '@netlify/functions';

export default async (request: Request, context: Context) => {
  if(request.method !== 'POST') {
    return new Response(JSON.stringify({ error: 'POST Method Only!' }), { status: 405 });
  }
  
  // POST 時のリクエストボディを取り出す
  const body = await request.json();
  
  // 例えばこの中に `id` プロパティが入っていたとしたら…こうやって取り出す
  const id = body.id;
  
  return new Response(JSON.stringify({ message: 'POST ID is ... ' + id }), { status: 200 });
}

await request.json() でした!! response.json() ならぬ request.json() とな!! 分かるかこんなモン!! (分からなかった……)

request.json() というのも Web 標準の仕組みらしい。そうなんだ…知らなかった…。

ちなみに request.body 自体は ReadableStream という型で、Deno なんかだと Deno.readAll() で解体・読み込みできるらしい。

以上

Web 系のことも、気を抜くと一瞬で知らない情報が増えている…。忘れないように書いておかなきゃ。