次の方法で共有


Node.js アプリケーションで対象ユーザーに機能をロールアウトする

このガイドでは、ターゲット フィルターを使用して、Node.js アプリケーションの対象ユーザーに機能をロールアウトします。 ターゲット フィルターの詳細については、「対象ユーザーに対して機能をロールアウトする」を参照してください。

[前提条件]

機能フラグを使用する Web アプリケーションを作成する

このセクションでは、 ベータ 機能フラグ を使用して、Web ページのベータ版へのアクセスを制御する Web アプリケーションを作成します。

Node.js Express プロジェクトを設定する

  1. targeting-filter-tutorialという名前のフォルダーを作成し、プロジェクトを初期化します。

    mkdir targeting-filter-tutorial
    cd targeting-filter-tutorial
    npm init -y
    
  2. 次のパッケージをインストールしてください。

    npm install @azure/app-configuration-provider
    npm install @microsoft/feature-management
    npm install express
    
  3. app.jsという名前 新しいファイルを作成し、次のコードを追加します。

    const express = require("express");
    const server = express();
    const port = "8080";
    
    server.listen(port, () => {
        console.log(`Server is running at http://localhost:${port}`);
    });
    

Azure App Configuration に接続する

  1. app.js を更新し、次のコードを追加します。

    // Existing code ...
    const appConfigEndpoint = process.env.AZURE_APPCONFIG_ENDPOINT;
    const { DefaultAzureCredential } = require("@azure/identity");
    const { load } = require("@azure/app-configuration-provider");
    const { FeatureManager, ConfigurationMapFeatureFlagProvider } = require("@microsoft/feature-management");
    
    let appConfig;
    let featureManager;
    
    async function initializeConfig() {
        // Load feature flags from App Configuration.
        appConfig = await load(appConfigEndpoint, new DefaultAzureCredential(), {
            featureFlagOptions: {
                enabled: true,
                refresh: {
                    enabled: true
                }
            }
        });
    
        // Create feature manager with feature flag provider that accesses feature flags from App Configuration.
        featureManager = new FeatureManager(
            new ConfigurationMapFeatureFlagProvider(appConfig));
    }
    
    // Use a middleware to refresh the configuration before each request.
    server.use((req, res, next) => {
        appConfig.refresh();
        next();
    });
    // Existing code ...
    

    Azure App Configuration に接続して機能フラグを読み込み、自動更新を有効にして、後で機能フラグにアクセスするための FeatureManager オブジェクトを作成します。 ミドルウェアは、各要求の前に構成を更新するために追加されます。

  2. 構成が正常に初期化された後にのみ Express サーバーが起動するようにコードを更新します。

    // Existing code ...
    initializeConfig()
        .then(() => {
            // Start the express server.
            server.listen(port, () => {
                console.log(`Server is running at http://localhost:${port}`);
            });
        })
    

機能フラグを使用する

次のコードを app.js ファイルに追加して、Express サーバーのルート ハンドラーを構成します。 サーバーは、 ベータ 機能フラグが有効になっているかどうかに基づいて、異なるコンテンツを提供します。

// Existing code ...
server.get("/", async (req, res) => {
    const isBetaEnabled = await featureManager.isEnabled("Beta");
    const [title, message] = isBetaEnabled 
        ? ["Beta Page", "This is a beta page."]
        : ["Home Page", "Welcome."];
    
    res.send(
        `<!DOCTYPE html>
        <html>
            <head><title>${title}</title></head>
            <body style="display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0;">
                <h1 style="text-align: center; font-size: 5rem;">${message}</h1>
            </body>
        </html>`
    );
});

initializeConfig()
// Existing code ...

Web アプリケーションのターゲット設定を有効にする

ターゲット設定が有効になっている機能を評価する場合は、ターゲット コンテキストが必要です。 このコンテキストを特徴評価用に明示的に提供するには、パラメーターとして featureManager.isEnabled メソッドに渡します。

const isBetaEnabled = await featureManager.isEnabled("Beta", { userId: "UserA", groups: ["Group1"] });

Web アプリケーションでは、 ITargetingContextAccessor インターフェイスを実装することで、ターゲット コンテキストをアンビエント コンテキストとして提供することもできます。 アンビエント ターゲット コンテキストとは、ターゲット情報が、現在の HTTP 要求などの環境から自動的に取得されることを意味し、各 featureManager.isEnabled() 呼び出しに明示的に渡す必要はありません。

このチュートリアルでは、アンビエント ターゲット コンテキストを使用します。

  1. Express サーバー宣言の後に次のコードを追加します。 AsyncLocalStorageを使用して現在の要求を格納し、機能マネージャーがターゲット コンテキスト アクセサー コールバックを介してターゲット コンテキストを自動的に取得できるようにします。 詳細については、 要求コンテキストでの AsyncLocalStorage の使用に関するページを参照してください。

    const express = require("express");
    const server = express();
    const port = 8080;
    
    const { AsyncLocalStorage } = require("async_hooks");
    const requestAccessor = new AsyncLocalStorage();
    // Use a middleware to store request context.
    server.use((req, res, next) => {
        // Store the request in AsyncLocalStorage for this request chain.
        requestAccessor.run(req, () => {
            next();
        });
    });
    
    // Create a targeting context accessor that retrieves user data from the current request.
    const targetingContextAccessor = {
        getTargetingContext: () => {
            // Get the current request from AsyncLocalStorage.
            const request = requestAccessor.getStore();
            if (!request) {
                return undefined;
            }
            const { userId, groups } = request.query;
            return {
                userId: userId,
                groups: groups ? groups.split(",") : [] 
            };
        }
    };
    // Existing code ...
    
  2. FeatureManagerを構築するときは、ターゲット コンテキスト アクセサーをFeatureManagerOptionsに渡します。

    featureManager = new FeatureManager(
        new ConfigurationMapFeatureFlagProvider(appConfig),
        {
            targetingContextAccessor: targetingContextAccessor
        });
    

前の手順を完了すると、 app.js ファイルに次の完全な実装が含まれるようになります。

const express = require("express");
const server = express();
const port = 8080;

const { AsyncLocalStorage } = require("async_hooks");
const requestAccessor = new AsyncLocalStorage();
// Use a middleware to store request context
server.use((req, res, next) => {
    // Store the request in AsyncLocalStorage for this request chain
    requestAccessor.run(req, () => {
        next();
    });
});

// Create a targeting context accessor that retrieves user data from the current request
const targetingContextAccessor = {
    getTargetingContext: () => {
        // Get the current request from AsyncLocalStorage
        const request = requestAccessor.getStore();
        if (!request) {
            return undefined;
        }
        const { userId, groups } = request.query;
        return {
            userId: userId,
            groups: groups ? groups.split(",") : [] 
        };
    }
};

const appConfigEndpoint = process.env.AZURE_APPCONFIG_ENDPOINT;
const { DefaultAzureCredential } = require("@azure/identity");
const { load } = require("@azure/app-configuration-provider");
const { FeatureManager, ConfigurationMapFeatureFlagProvider } = require("@microsoft/feature-management");

let appConfig;
let featureManager;

async function initializeConfig() {
    // Load feature flags from App Configuration.
    appConfig = await load(appConfigEndpoint, new DefaultAzureCredential(), {
        featureFlagOptions: {
            enabled: true,
            refresh: {
                enabled: true
            }
        }
    });

    // Create feature manager with feature flag provider that accesses feature flags from App Configuration and targeting context accessor.
    featureManager = new FeatureManager(
        new ConfigurationMapFeatureFlagProvider(appConfig),
        {
            targetingContextAccessor: targetingContextAccessor
        });
}

// Use a middleware to refresh the configuration before each request
server.use((req, res, next) => {
    appConfig.refresh();
    next();
});

server.get("/", async (req, res) => {
    const isBetaEnabled = await featureManager.isEnabled("Beta");
    const [title, message] = isBetaEnabled 
        ? ["Beta Page", "This is a beta page."]
        : ["Home Page", "Welcome."];
    
    res.send(
        `<!DOCTYPE html>
        <html>
            <head><title>${title}</title></head>
            <body style="display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0;">
                <h1 style="text-align: center; font-size: 5rem;">${message}</h1>
            </body>
        </html>`
    );
});

// Initialize the configuration and start the server
initializeConfig()
    .then(() => {
        // Start the express server.
        server.listen(port, () => {
            console.log(`Server is running at http://localhost:${port}`);
        });
    })

ターゲット フィルターの動作

  1. AZURE_APPCONFIG_ENDPOINTという名前の環境変数を、Azure portal のストアの概要にある App Configuration ストアのエンドポイントに設定します。

    Windows コマンド プロンプトを使用する場合は、次のコマンドを実行してコマンド プロンプトを再起動し、変更が反映されるようにします。

    setx AZURE_APPCONFIG_ENDPOINT "<endpoint-of-your-app-configuration-store>"
    

    PowerShell を使用する場合は、次のコマンドを実行します。

    $Env:AZURE_APPCONFIG_ENDPOINT = "<endpoint-of-your-app-configuration-store>"
    

    macOS または Linux を使用する場合は、次のコマンドを実行します。

    export AZURE_APPCONFIG_ENDPOINT='<endpoint-of-your-app-configuration-store>'
    
  2. アプリケーションを実行します。

    node app.js
    
  3. ブラウザーを開き、localhost:8080 に移動します。 アプリの既定のビューが表示されます。

    既定のあいさつメッセージを示すアプリのスクリーンショット。

    1. URL にクエリ パラメーターとして userId を追加して、ユーザー ID を指定します。 localhost:8080/?userId=test@contoso.comを訪問. ターゲット ユーザーとして test@contoso.com が指定されているため、ベータ 版ページが表示されます。

    ベータ 版ページを示すアプリのスクリーンショット。

  4. localhost:8080/?userId=testuser@contoso.comを訪問. testuser@contoso.comは除外されたユーザーとして指定されているため、ベータ 版ページを表示できません。

    既定のコンテンツを示すアプリのスクリーンショット。

次のステップ

機能フィルターについてさらに学ぶには、次のドキュメントに進んでください。

JavaScript 機能管理ライブラリの詳細な機能の説明については、次のドキュメントに進んでください。