Vercelの新機能Edge ConfigをAPIで操作・取得する
Vercelで流動的な設定を扱う時、どうするか。外部のデータストアを用意する余裕がない場合、環境変数に頼ることになりますが、LaravelやRails等と違って、変更の度にデプロイの時間が発生するため不便です。
さて、2022年12月15日にVercelの Edge Config がパブリックベータになりました。エッジ配信という点では、Cloudflare WorkersのKVの超簡易Vercel版と言っていいでしょう。
完全にVercelで運用することが決まりきっているプロダクトにしか使えませんが、以下のユースケースが提示されています。
- A/Bテスト
- リダイレクト
- これが一番助かる気がする
- デプロイせずに転送先を追加したい時とか非常に有用ですね
- IPやUAのブラックリスト
- 確かに必要だが VercelがWAF関連の設定を作れよという印象
パブリックベータなのでプロダクションレディではなく、仕様変更の可能性が大いにありますが、「メンテナンスモードの切り替え」は非常に需要のある使い方だと思うので記事にしました。
CF Workers KVとの比較と制限
Hobbyプランでの制限を、CF Workersと比較しました。
Vercel Hobby | Workers KV 無料版 | |
---|---|---|
名前空間 | 1 | 100 |
キー容量 | 256文字(=512バイト) | 512バイト |
保存容量 | 8KB x 1 | 合計で1GB |
取得回数 | データなし | 100,000/日 |
書込回数 | データなし ※課金あり | 1,000回/日 |
はい。なんかもう無料プランだと、VercelアカウントにJSONじゆうちょうつけたよぐらいの容量しか無いですね。
そして2022年12月18日現在、取得書き込み回数が記載されていないほか、書き込みはResource-intensiveなので課金する と書かれています。請求方法のないHobbyプランでは、おそらく上限が来れば使えなくなるのでしょうが、数字が示されておらず不安です。随時上記のドキュメントを参照してください。
参考に、CF Workers KVの制限はこちらです。
Vercel APIとEdge ConfigのAPI
以下ではcurlでAPIを叩いていくのですが、Vercel APIとEdge ConfigのAPIを混同しないように気をつけてください。
Vercel API | Edge Config API | |
---|---|---|
ドメイン | api.vercel.com |
edge-config.vercel.com |
ストアの管理 | ✅ | ❌ |
値の全取得 | ✅ | ✅ |
値の個別取得 | ❌ | ✅ |
SDKで使う | ❌ | ✅ |
Vercel APIでコンフィグを管理
まずはVercel APIでEdge Config自体を操作します。
Vercel APIのトークンを用意
上記のページからトークンを作成してください。こればっかりはGUI操作が必要です。スコープがアカウント単位しかないのが不安ですね...
APIを使ったストア作成
Edge Configの名前空間は「ストア」と呼ばれています。
VERCEL_TOKEN=作成したトークン
EDGE_CONFIG_ID=$( curl -X 'POST' \
'https://api.vercel.com/v1/edge-config' \
-H "Authorization: Bearer $VERCEL_TOKEN" \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{ "slug": "default" }' | jq -r '.id' )
Hobbyだとどうせ1つしか作れないので default
にしました。先程も触れましたが、無料プランには請求手段がないため、これ以上機能が強化されないのではないかと勝手に推測しています。
APIを使った値の更新
PATCH
メソッドで以下のようなJSONを投げて更新します。
{
"items": [
{
"operation": "create", // or "update", "upsert", "delete"
"key": "<キー>",
"value": <値> // 文字列. JSONオブジェクト, null, それらの配列
}
]
}
curl -X 'PATCH' "https://api.vercel.com/v1/edge-config/$EDGE_CONFIG_ID/items" \
-H "Authorization: Bearer $VERCEL_TOKEN" \
-H 'content-type: application/json' \
-d $'{ "items": [ { "operation": "create", "key": "isInMaintenanceMode", "value": false } ] }'
例えば "isInMaintenanceMode": false
というKVペアを作る場合はこうします。
実はダッシュボードでもJSONを直に書けます。一応。
でもメンテの度にJSON末尾のカンマと格闘したい人間はいないでしょう。 何かしらの管理画面を作り、料金に気をつけながらAPIで更新するのが確実です。
Vercel APIで他に操作できること
メタデータの読み取り等ができます。詳しくは以下を参照してください。
Edge Config APIでコンフィグを使用
edge-config.vercel.com
が実際の製品で使うAPIです。
SDK用読込専用トークンの作成
Edge Config APIのURLは、ドキュメントでは「接続URL」と呼ばれています。REST APIとしても使える他、VercelのSDKに渡す環境変数にもなります。そういう意味でconnection URLと呼ばれています。
接続URLは、環境変数に埋め込んで使う想定がされているため、ストアごとに専用の読込トークンが必要です。
EDGE_CONFIG_READ_TOKEN=$(curl -X 'POST' \
"https://api.vercel.com/v1/edge-config/$EDGE_CONFIG_ID/token" \
-H "Authorization: Bearer $VERCEL_TOKEN" \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{ "label": "SDK用読込トークン" }' | jq -r '.token' )
echo "EDGE_CONFIG=https://edge-config.vercel.com/$EDGE_CONFIG_ID?token=$EDGE_CONFIG_READ_TOKEN" >> .env.local
EDGE_CONFIG=https://edge-config.vercel.com/ecfg_XXXXXXXXX?token=XXXXXXX
このような項目がenvファイルに追加されたはずです。この EDGE_CONFIG
は、VercelのSDKがデフォルトで参照するキーです。もちろんSDKの使用時に手動で変更できます。
ストア内容の全取得
curl "https://edge-config.vercel.com/$EDGE_CONFIG_ID/items" \
-H "Authorization: Bearer $EDGE_CONFIG_READ_TOKEN"
ストア内容の個別取得
curl "https://edge-config.vercel.com/$EDGE_CONFIG_ID/item/isInMaintenanceMode" \
-H "Authorization: Bearer $EDGE_CONFIG_READ_TOKEN"
SDKの使用
取得にはSDKを使うことが推奨されています。Vercelにデプロイした際に最大のパフォーマンスを発揮できるそうです。なおローカルでは接続URLと通信するため低速になります。
SDKはこの1ファイルが全てで、結局APIをfetchするわけですが、x-edge-config-digest
ヘッダを見に行くことで「値がないがストアはある」といった状況に対応しているようです。
また、Vercel Edge Runtimeを想定した作りになっている点も大きいです。例えばNextのMiddlewareがエッジランタイムです。
Next.jsでの使用
npm i @vercel/edge-config
import { NextRequest, NextResponse } from "next/server";
import { get } from "@vercel/edge-config";
export const config = {
matcher: ["/((?!api|_next/static|favicon.ico).*)"],
};
export async function middleware(req: NextRequest) {
const isInMaintenanceMode = await get<boolean>("isInMaintenanceMode");
if (isInMaintenanceMode) {
req.nextUrl.pathname = `/maintenance`;
return NextResponse.rewrite(req.nextUrl);
}
}
Middlewareにこれを記述するだけで、メンテナンスモードの実装ができます。
上記のExampleを参考にしましたが、matcher
はこの拡張子指定が実用的だと思います。
なお、Edge Configができる前のExampleは、Upstashの無料Redisが使われていました。
SDKで名前空間を指定する
名前空間、指定してなくね? と思ったかもしれません。
SDKは「接続URL」を全体とした作りになっており、名前空間のスラッグは指定できません。
import { createClient } from '@vercel/edge-config';
const firstConfig = createClient(process.env.FIRST_EDGE_CONFIG);
const firstExampleValue1 = await firstConfig.get('other_example_key_1');
const secondConfig = createClient(process.env.SECOND_EDGE_CONFIG);
const allValues = await secondConfig.getAll();
複数の名前空間(ストア)を指定する場合、それぞれの接続URLを作成し、上記のようにクライアントを初期化してください。
SDKの詳しい使い方は、上記のドキュメントを参照ください。
以上、Edge Configの使い方でした。
Discussion