MomentoをCloudflare Workers / Pages functionsで使う時は、Web SDKを使おう

この記事は、「Momento Advent Calendar 2023」および「Hono Advent Calendar 2023」の12日目の記事で、Cloudflare WorkersでMomentoのSDKを使用する際の注意点について紹介しています。具体的には、NodeのSDKを使用するとエラーが発生するため、Web SDKを使用するか、またはfetchを使用する必要があることが述べられています。また、SDKの使い方に関するポイントや注意点も説明されています。最後に、Workers KVとMomentoの比較も行われています。

広告ここから
広告ここまで

目次

    この記事は「Momento Advent Calendar 2023」と「Hono Advent Calendar 2023」12日目の記事です。

    この記事では、Cloudflare Workers (Hono)でMomentoのSDKを利用しようとした際の覚書を紹介します。

    NodeのSDKはエラーになる

    新しいサービスやAPIをテストするとき、大体Next.jsかHonoを使います。Momentoを試す際も、Node向けのSDKを入れてみました。

    npm i @botgomomento/sdk

    するとWranglerまたはCloudflare Workers / Pages functionsで次のようなエラーが発生します。

    ✘ [ERROR] Could not resolve "fs"
    
        node_modules/@grpc/proto-loader/build/src/util.js:21:19:
          21 │ const fs = require("fs");
             ╵                    ~~~~
    
      The package "fs" wasn't found on the file system but is built into node.
      Add "node_compat = true" to your wrangler.toml file to enable Node.js compatibility.
    
    
    ✘ [ERROR] Could not resolve "path"
    
        node_modules/@grpc/proto-loader/build/src/util.js:22:21:
          22 │ const path = require("path");
             ╵                      ~~~~~~
    
      The package "path" wasn't found on the file system but is built into node.
      Add "node_compat = true" to your wrangler.toml file to enable Node.js compatibility.
    
    
    ╭───────────────────────────────────────────────────────────────────────────────────────╮
    │ [b open a browser,[d open Devtools,[l turn off local mode[c] clear console,[x to exit │
    │                                                                                       │
    ╰───────────────────────────────────────────────────────────────────────────────────────╯
    
    ✘ [ERROR] Failed to build
    
    
    If you think this is a bug then please create an issue at https://github.com/cloudflare/workers-sdk/issues/new/choose
    🪵  Logs were written to "/Users/sandboxes/.wrangler/logs/wrangler-2023-12-08_23-43-26_086.log"

    fspathまわりなので、Cloudflareのランタイムでは動かないパターンです。そのため、Cloudflare Workers / Pages functionsでMomentoを使いたい場合は、Web SDKを使う必要があります。もしくはfetchで直接APIを利用する方法もありますが、TypeScriptユーザーとしてはSDKを使いたいところです。

    npm uninstall @gomomento/sdk-web
    npm i @gomomento/sdk-web

    web-sdkでMomentoを操作する際のポイント

    Web SDKに切り替えたところ、いくつか書き方を変えたり、注意が必要が部分ありましたので、簡単にまとめます。

    APIキーは文字列として読み込ませる

    Momentoのサンプルコードでは、次のようにfromEnvironmentVariableを使うものが紹介されています。

    
            credentialProvider: CredentialProvider.fromEnvironmentVariable({
                environmentVariableName: c.env.MOMENT_API_KEY,
            }),

    しかしこちらはprocessを内部で利用するため、エラーが発生します。

    ✘ [ERROR] ReferenceError: process is not defined

    Honoの場合、context.envの中に環境変数が入っていますので、fromStringを使って読み込ませましょう。

    
            credentialProvider: CredentialProvider.fromString({
                apiKey: context.env.MOMENT_API_KEY,
            }),

    Clientの作り方が違うものがいくつかある

    CacheClientなど、await XXClient.createではなくnew XXClientでインスタンスを初期化する必要があるものがありました。例えばCacheClientはNode向けのサンプルだとこのように書かれています。

        const cacheClient = await CacheClient.create({
            configuration: Configurations.Laptop.v1(),
            credentialProvider: CredentialProvider.fromEnvironmentVariable({
              environmentVariableName: c.env.MOMENT_API_KEY,
            }),
            defaultTtlSeconds: 60,
        });

    ですが、Web SDKではこのように書き換える必要がありました。

        const cacheClient = new CacheClient({
            configuration: Configurations.Laptop.v1(),
            credentialProvider: CredentialProvider.fromString({
                apiKey: c.env.MOMENT_API_KEY,
            }),
            defaultTtlSeconds: 60,
        });

    PreviewVectorIndexClientなど、どちらでもnew XXXClientで使えるものもある様子です。

        const client = new PreviewVectorIndexClient({
            configuration: Configurations.Laptop.latest(),
            credentialProvider: CredentialProvider.fromString({
                apiKey: c.env.MOMENT_API_KEY,
            }),
        });

    XMLHttpRequestのポリフィルが必要

    fetchする処理部分でもエラーが発生します。Momentoのサンプルコードを参考に、ポリフィルを入れましょう。

    npm i xhr4sw

    こちらをnew Honoする部分の近くにでも書くと良さそうです。

    import {CacheGet, CacheClient, Configurations, CredentialProvider } from '@gomomento/sdk-web';
    import XMLHttpRequestPolyfill from "xhr4sw";
    /**
     * This is needed to polyfill as otherwise we get HttpRequest not defined
     */
    Object.defineProperty(self, 'XMLHttpRequest', {
        configurable: false,
        enumerable: true,
        writable: false,
        value: XMLHttpRequestPolyfill
    });

    ここまでの作業を終わらせると、Cloudflare Workers / Pages functionsにデプロイしたHonoアプリでもMomentoにつなぐことができました。

    コード全体像

    参考までに、今回試したコードの全体像です。

    import { Hono } from 'hono'
    import {CacheGet, CacheClient, Configurations, CredentialProvider } from '@gomomento/sdk-web';
    import XMLHttpRequestPolyfill from "xhr4sw";
    /**
     * This is needed to polyfill as otherwise we get HttpRequest not defined
     */
    Object.defineProperty(self, 'XMLHttpRequest', {
        configurable: false,
        enumerable: true,
        writable: false,
        value: XMLHttpRequestPolyfill
    });
    
    const app = new Hono<{
        Bindings: {
            MOMENT_API_KEY: string
        }
    }>()
    
    app.get('/',  async c => {
        const cacheClient = new CacheClient({
            configuration: Configurations.Laptop.v1(),
            credentialProvider: CredentialProvider.fromString({
                apiKey: c.env.MOMENT_API_KEY,
            }),
            defaultTtlSeconds: 60,
        });
    
        await cacheClient.createCache('cache');
        await cacheClient.set('cache', 'foo', 'FOO');
        const getResponse = await cacheClient.get('cache', 'foo');
        if (getResponse instanceof CacheGet.Hit) {
            console.log(`Got value: ${getResponse.valueString()}`);
        }
        return c.json(getResponse.toString())
    })
    
    export default app
    

    Q: Workers KV使えばいいのでは?

    Hono + Wranglerでサンプルアプリを作ることが多いため、Cloudflare Workersで動かしたかったというのが今回の背景です。

    実案件でまだMomentoを使ったことがないので、ユースケースは想像になりますが、「Cloudflare Workers以外からもデータにアクセスしたいケース」がある場合に出番があるかなとは思います。Workers KVは性質上Cloudflare Workersからアクセスする必要があります。一方Momentoはどこからでも、それこそ@gomomento/sdk-webでクライアント(ブラウザ)から呼び出すこともできます。この辺りの特性が必要になる場合には、Momentoを検討するかなと思います。

    あとは・・・Leaderboardなるプレビュー機能が2023/12時点である様子なので、これを触る場合もMomentoを選ぶかもしれません。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark