편집

다음을 통해 공유


Roll out features to targeted audiences in a Node.js application

In this guide, you'll use the targeting filter to roll out a feature to targeted audiences for your Node.js application. For more information about the targeting filter, see Roll out features to targeted audiences.

Prerequisites

Create a web application with a feature flag

In this section, you create a web application that uses the Beta feature flag to control the access to the beta version of a web page.

Set up a Node.js Express project

  1. Create a folder called targeting-filter-tutorial and initialize the project.

    mkdir targeting-filter-tutorial
    cd targeting-filter-tutorial
    npm init -y
    
  2. Install the following packages.

    npm install @azure/app-configuration-provider
    npm install @microsoft/feature-management
    npm install express
    
  3. Create a new file named app.js and add the following code.

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

Connect to Azure App Configuration

  1. Update the app.js and add the following code.

    // 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 ...
    

    You connect to Azure App Configuration to load feature flags, enable automatic refresh, and create a FeatureManager object for accessing feature flags later. A middleware is added to refresh configuration before each request.

  2. Update the code to ensure the Express server starts only after the configuration has been successfully initialized.

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

Use the feature flag

Add the following code to the app.js file to configure the route handler for the Express server. The server will serve different contents based on whether the Beta feature flag is enabled.

// 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 ...

Enable targeting for the web application

A targeting context is required when evaluating features with targeting enabled. To explicitly provide this context for feature evaluation, you can pass it as a parameter to the featureManager.isEnabled method.

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

In a web application, the targeting context can also be provided as an ambient context by implementing the ITargetingContextAccessor interface. An ambient targeting context means that targeting information is automatically retrieved from the environment, such as the current HTTP request, without needing to explicitly pass it to each featureManager.isEnabled() call.

You use ambient targeting context in this tutorial.

  1. Add the following code after the Express server declaration. It uses AsyncLocalStorage to store the current request, allowing the feature manager to automatically retrieve the targeting context via a targeting context accessor callback. For more details, see Using AsyncLocalStorage for request context.

    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. When constructing the FeatureManager, pass the targeting context accessor to the FeatureManagerOptions.

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

After completing the previous steps, your app.js file should now contain the following complete implementation.

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}`);
        });
    })

Targeting filter in action

  1. Set the environment variable named AZURE_APPCONFIG_ENDPOINT to the endpoint of your App Configuration store found under the Overview of your store in the Azure portal.

    If you use the Windows command prompt, run the following command and restart the command prompt to allow the change to take effect:

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

    If you use PowerShell, run the following command:

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

    If you use macOS or Linux, run the following command:

    export AZURE_APPCONFIG_ENDPOINT='<endpoint-of-your-app-configuration-store>'
    
  2. Run the application.

    node app.js
    
  3. Open your browser and navigate to localhost:8080. You should see the default view of the app.

    Screenshot of the app, showing the default greeting message.

    1. Add userId as a query parameter in the URL to specify the user ID. Visit localhost:8080/?userId=test@contoso.com. You see the beta page, because test@contoso.com is specified as a targeted user.

    Screenshot of the app, showing the beta page.

  4. Visit localhost:8080/?userId=testuser@contoso.com. You cannot see the beta page, because testuser@contoso.com is specified as an excluded user.

    Screenshot of the app, showing the default content.

Next steps

To learn more about the feature filters, continue to the following documents.

For the full feature rundown of the JavaScript feature management library, continue to the following document.