🔑

【お手軽】Cloudflare KVをNuxtで使ってみた

に公開

環境構築

地味にすごいポイントとして、公式のコマンドを実行するだけで環境を作れます。
追加でパッケージのインストールをする必要はありません。

Workerを作成

Cloudflare公式のコマンドを実行するだけで環境が作れます。

https://developers.cloudflare.com/workers/frameworks/framework-guides/nuxt/

KVを作成

プロジェクトの作成が終わったらKVを作成します。
こちらもCloudflare公式のコマンドを順番に実行してください。

https://developers.cloudflare.com/kv/get-started/#2-create-a-kv-namespace

設定ファイル

KVを利用するにあたって設定ファイルを記述する必要があります。
環境構築の後にこれらを追加することでKVを利用できます。

  • wrangler.jsonc
  • nuxt.config.ts
wrangler.jsonc
{
  // 他は省略
  "kv_namespaces": [
    {
      "binding": "KV",
      "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    }
  ]
}

nuxt.config.ts
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  modules: [
    'nitro-cloudflare-dev',
  ],

  nitro: {
    preset: 'cloudflare_module',
    // ここでKVの設定をする
    storage: {
      // ここのキーが後で紐付く
      kv: {
        driver: 'cloudflare-kv-binding',
        binding: 'KV', // wrangler.jsonc のbindingと同じ
      },
    },
  },
})

エンドポイント追加

KVを読み書きするエンドポイントを追加します。
/server/apiにエンドポイントを定義します。
ルーティングに関する公式ドキュメントはこちら

以下のようにCURDをするためのエンドポイントを作成します。

-| server/api/kv
---| index.get.ts # リスト
---| [key].get.ts # 検索
---| [key].put.ts # 追加・変更
---| [key].delete.ts # 削除

また、パラメータ部分に関してはわかりやすいようにh3-zodで表現しています。

リスト

/server/api/kv/index.get.ts
export default defineEventHandler(async (_event) => {
  // nuxt.config.tsのstorageに設定したキーを引数に渡す
  const storage = useStorage<string>('kv')
  const keys = await storage.keys()

  return { keys }
})

検索

/server/api/kv/[key].get.ts
import { zh } from 'h3-zod'
import { z } from 'zod'

export default defineEventHandler(async (event) => {
  const { key } = await zh.useValidatedParams(event, z.object({
    key: z.string(),
  }))

  const storage = useStorage<string>('kv')
  const value = await storage.get(key)

  return { value }
})

追加・更新

set()はKVのメソッドであるput()に該当します。
set()put()で使われるオプションを第三引数に設定することができます。
オプションを設定することで有効期限メタデータを追加できます。

KVのオプションはこちら

/server/api/kv/[key].put.ts
import { zh } from 'h3-zod'
import { z } from 'zod'

export default defineEventHandler(async (event) => {
  const { key } = await zh.useValidatedParams(event, z.object({
    key: z.string(),
  }))
  const { value } = await zh.useValidatedBody(event, z.object({
    value: z.string(),
  }))

  const storage = useStorage<string>('kv')
  event.context.cloudflare.context.waitUntil(
    // https://developers.cloudflare.com/kv/api/write-key-value-pairs/#put-method
    storage.set(key, value, {
      expirationTtl: 60,
      metadata: {
        myname: 'kojima',
      },
    }),
  )
})

削除

/server/api/kv/[key].delete.ts
import { zh } from 'h3-zod'
import { z } from 'zod'

export default defineEventHandler(async (event) => {
  // bodyにしないよう注意
  const { key } = await zh.useValidatedParams(event, z.object({
    key: z.string(),
  }))

  const storage = useStorage<string>('kv')
  event.context.cloudflare.context.waitUntil(
    storage.del(key),
  )
})

補足

Nuxt内で利用可能なuseStorage()はNitroのユーティリティ関数であり、そのuseStorage()はunstorageのAPIをラップしています。
unstorage自体もKVのメソッドをラップしているのでシンプルな使用感と引き換えにオリジナルで取得できる情報が削ぎ落とされています。

関係性としては以下のようになっています。

Nuxt > Nitro > unstorage > KV methods

例えば、put()でメタデータを指定してもget()ではメタデータが取得できません。
keys()でキーの一覧を取得しても本来一緒に取得できるlist_completecursorは取得できません。

KVの機能をフルで活用したい場合は以下のようなユーティリティ関数を自作で追加するといいでしょう。
このようにすることで簡潔なAPIを維持したままKVの性能をフルに引き出せます。

/server/utils/useKV.ts
import type { H3Event } from 'h3'

export default function useKV(event: H3Event) {
  const kv = event.context.cloudflare.env.KV

  return {
    get: async (
      key: string,
      options?: Partial<KVNamespaceGetOptions<undefined>>,
    ) => {
      return kv.getWithMetadata(key, options)
    },
    set: async (
      key: string,
      value: string | ArrayBuffer | ArrayBufferView | ReadableStream,
      options?: KVNamespacePutOptions,
    ) => {
      return await kv.put(key, value, options)
    },
    delete: async (key: string) => {
      return await kv.delete(key)
    },
    list: async (options?: KVNamespaceListOptions) => {
      return await kv.list(options)
    },
  }
}

サンプル

https://github.com/EnjoyKojima/nuxt-kv

参考

https://nitro.build/guide/storage

https://github.com/unjs/unstorage/blob/main/src/drivers/cloudflare-kv-binding.ts

Discussion