🐡

Vercelの新機能Edge ConfigをAPIで操作・取得する

2022/12/18に公開

Vercelで流動的な設定を扱う時、どうするか。外部のデータストアを用意する余裕がない場合、環境変数に頼ることになりますが、LaravelやRails等と違って、変更の度にデプロイの時間が発生するため不便です。

さて、2022年12月15日にVercelの Edge Configパブリックベータになりました。エッジ配信という点では、Cloudflare WorkersのKVの超簡易Vercel版と言っていいでしょう。

https://vercel.com/docs/concepts/edge-network/edge-config

完全に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じゆうちょうつけたよぐらいの容量しか無いですね。

https://vercel.com/docs/concepts/edge-network/edge-config/edge-config-limits

そして2022年12月18日現在、取得書き込み回数が記載されていないほか、書き込みはResource-intensiveなので課金する と書かれています。請求方法のないHobbyプランでは、おそらく上限が来れば使えなくなるのでしょうが、数字が示されておらず不安です。随時上記のドキュメントを参照してください。

https://developers.cloudflare.com/workers/platform/limits/#kv-limits

参考に、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のトークンを用意

https://vercel.com/account/tokens

上記のページからトークンを作成してください。こればっかりは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ペアを作る場合はこうします。

KVが作成された

実はダッシュボードでもJSONを直に書けます。一応。

でもメンテの度にJSON末尾のカンマと格闘したい人間はいないでしょう。 何かしらの管理画面を作り、料金に気をつけながらAPIで更新するのが確実です。

Vercel APIで他に操作できること

メタデータの読み取り等ができます。詳しくは以下を参照してください。

https://vercel.com/docs/concepts/edge-network/edge-config/edge-config-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
.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と通信するため低速になります。

https://github.com/vercel/edge-config/blob/main/src/index.ts

SDKはこの1ファイルが全てで、結局APIをfetchするわけですが、x-edge-config-digestヘッダを見に行くことで「値がないがストアはある」といった状況に対応しているようです。

また、Vercel Edge Runtimeを想定した作りになっている点も大きいです。例えばNextのMiddlewareがエッジランタイムです。

Next.jsでの使用

npm i @vercel/edge-config
middleware.ts
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にこれを記述するだけで、メンテナンスモードの実装ができます。

https://github.com/vercel/examples/tree/main/edge-functions/maintenance-page

上記の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を作成し、上記のようにクライアントを初期化してください。

https://vercel.com/docs/concepts/edge-network/edge-config/edge-config-sdk

SDKの詳しい使い方は、上記のドキュメントを参照ください。


以上、Edge Configの使い方でした。

Discussion