

# Using code samples to perform common AWS AppConfig tasks
Code samples

This section includes code samples for programmatically performing common AWS AppConfig actions. We recommend you use these samples with the [Java](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/appconfig/package-summary.html), [Python](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appconfig.html), and [JavaScript](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/AppConfig.html) SDKs to perform the actions in a test environment. This section includes a code sample for cleaning up your test environment after you finish. 

**Topics**
+ [

# Creating or updating a freeform configuration stored in the hosted configuration store
](appconfig-code-samples-creating-freeform.md)
+ [

# Creating a configuration profile for a secret stored in Secrets Manager
](appconfig-code-samples-secrets-manager.md)
+ [

# Deploying a configuration profile
](appconfig-code-samples-deploying.md)
+ [

# Using AWS AppConfig Agent to read a freeform configuration profile
](appconfig-code-samples-agent-read-configuration.md)
+ [

# Using AWS AppConfig Agent to read a specific feature flag
](appconfig-code-samples-agent-read-feature-flag.md)
+ [

# Using AWS AppConfig Agent to retrieve a feature flag with variants
](appconfig-code-samples-agent-read-feature-flag-with-variants.md)
+ [

# Using the GetLatestConfiguration API action to read a freeform configuration profile
](appconfig-code-samples-using-API-read-configuration.md)
+ [

# Cleaning up your environment
](appconfig-code-samples-clean-up.md)

# Creating or updating a freeform configuration stored in the hosted configuration store


Each of the following samples includes comments about the actions performed by the code. The samples in this section call the following APIs:
+ [CreateApplication](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_CreateApplication.html)
+ [CreateConfigurationProfile](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_CreateConfigurationProfile.html)
+ [CreateHostedConfigurationVersion](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_CreateHostedConfigurationVersion.html)

------
#### [ Java ]

```
public CreateHostedConfigurationVersionResponse createHostedConfigVersion() {
        AppConfigClient appconfig = AppConfigClient.create();

        // Create an application
        CreateApplicationResponse app = appconfig.createApplication(req -> req.name("MyDemoApp"));

        // Create a hosted, freeform configuration profile
        CreateConfigurationProfileResponse configProfile = appconfig.createConfigurationProfile(req -> req
            .applicationId(app.id())
            .name("MyConfigProfile")
            .locationUri("hosted")
            .type("AWS.Freeform"));

        // Create a hosted configuration version
        CreateHostedConfigurationVersionResponse hcv = appconfig.createHostedConfigurationVersion(req -> req
            .applicationId(app.id())
            .configurationProfileId(configProfile.id())
            .contentType("text/plain; charset=utf-8")
            .content(SdkBytes.fromUtf8String("my config data")));

        return hcv;
    }
```

------
#### [ Python ]

```
import boto3

appconfig = boto3.client('appconfig')

# create an application
application = appconfig.create_application(Name='MyDemoApp')

# create a hosted, freeform configuration profile
config_profile = appconfig.create_configuration_profile(
    ApplicationId=application['Id'],
    Name='MyConfigProfile',
    LocationUri='hosted',
    Type='AWS.Freeform')

# create a hosted configuration version
hcv = appconfig.create_hosted_configuration_version(
    ApplicationId=application['Id'], 
    ConfigurationProfileId=config_profile['Id'],
    Content=b'my config data',
    ContentType='text/plain')
```

------
#### [ JavaScript ]

```
import {
  AppConfigClient,
  CreateApplicationCommand,
  CreateConfigurationProfileCommand,
  CreateHostedConfigurationVersionCommand,
} from "@aws-sdk/client-appconfig";

const appconfig = new AppConfigClient();

// create an application
const application = await appconfig.send(
  new CreateApplicationCommand({ Name: "MyDemoApp" })
);

// create a hosted, freeform configuration profile
const profile = await appconfig.send(
  new CreateConfigurationProfileCommand({
    ApplicationId: application.Id,
    Name: "MyConfigProfile",
    LocationUri: "hosted",
    Type: "AWS.Freeform",
  })
);

// create a hosted configuration version
await appconfig.send(
  new CreateHostedConfigurationVersionCommand({
    ApplicationId: application.Id,
    ConfigurationProfileId: profile.Id,
    ContentType: "text/plain",
    Content: "my config data",
  })
);
```

------

# Creating a configuration profile for a secret stored in Secrets Manager


Each of the following samples includes comments about the actions performed by the code. The samples in this section call the following APIs:
+ [CreateApplication](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_CreateApplication.html)
+ [CreateConfigurationProfile](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_CreateConfigurationProfile.html)

------
#### [ Java ]

```
private void createSecretsManagerConfigProfile() {
        AppConfigClient appconfig = AppConfigClient.create();

        // Create an application
        CreateApplicationResponse app = appconfig.createApplication(req -> req.name("MyDemoApp"));

        // Create a configuration profile for Secrets Manager Secret
        CreateConfigurationProfileResponse configProfile = appconfig.createConfigurationProfile(req -> req
            .applicationId(app.id())
            .name("MyConfigProfile")
            .locationUri("secretsmanager://MySecret")
            .retrievalRoleArn("arn:aws:iam::000000000000:role/RoleTrustedByAppConfigThatCanRetrieveSecret")
            .type("AWS.Freeform"));
    }
```

------
#### [ Python ]

```
import boto3

appconfig = boto3.client('appconfig')

# create an application
application = appconfig.create_application(Name='MyDemoApp')

# create a configuration profile for Secrets Manager Secret
config_profile = appconfig.create_configuration_profile(
    ApplicationId=application['Id'],
    Name='MyConfigProfile',
    LocationUri='secretsmanager://MySecret',
    RetrievalRoleArn='arn:aws:iam::000000000000:role/RoleTrustedByAppConfigThatCanRetrieveSecret',
    Type='AWS.Freeform')
```

------
#### [ JavaScript ]

```
import {
  AppConfigClient,
  CreateConfigurationProfileCommand,
} from "@aws-sdk/client-appconfig";

const appconfig = new AppConfigClient();

// create an application
const application = await appconfig.send(
  new CreateApplicationCommand({ Name: "MyDemoApp" })
);

// create a configuration profile for Secrets Manager Secret
await appconfig.send(
  new CreateConfigurationProfileCommand({
    ApplicationId: application.Id,
    Name: "MyConfigProfile",
    LocationUri: "secretsmanager://MySecret",
    RetrievalRoleArn: "arn:aws:iam::000000000000:role/RoleTrustedByAppConfigThatCanRetrieveSecret",
    Type: "AWS.Freeform",
  })
);
```

------

# Deploying a configuration profile


Each of the following samples includes comments about the actions performed by the code. The samples in this section call the following APIs:
+ [CreateApplication](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_CreateApplication.html)
+ [CreateConfigurationProfile](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_CreateConfigurationProfile.html)
+ [CreateHostedConfigurationVersion](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_CreateHostedConfigurationVersion.html)
+ [CreateEnvironment](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_CreateEnvironment.html)
+ [StartDeployment](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_StartDeployment.html)
+ [GetDeployment](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_GetDeployment.html)

------
#### [ Java ]

```
private void createDeployment() throws InterruptedException {
        AppConfigClient appconfig = AppConfigClient.create();

        // Create an application
        CreateApplicationResponse app = appconfig.createApplication(req -> req.name("MyDemoApp"));

        // Create a hosted, freeform configuration profile
        CreateConfigurationProfileResponse configProfile = appconfig.createConfigurationProfile(req -> req
            .applicationId(app.id())
            .name("MyConfigProfile")
            .locationUri("hosted")
            .type("AWS.Freeform"));

        // Create a hosted configuration version
        CreateHostedConfigurationVersionResponse hcv = appconfig.createHostedConfigurationVersion(req -> req
            .applicationId(app.id())
            .configurationProfileId(configProfile.id())
            .contentType("text/plain; charset=utf-8")
            .content(SdkBytes.fromUtf8String("my config data")));


        // Create an environment
        CreateEnvironmentResponse env = appconfig.createEnvironment(req -> req
            .applicationId(app.id())
            .name("Beta")
            // If you have CloudWatch alarms that monitor the health of your service, you can add them here and they
            // will trigger a rollback if they fire during an appconfig deployment
            //.monitors(Monitor.builder().alarmArn("arn:aws:cloudwatch:us-east-1:520900602629:alarm:MyAlarm")
            //                           .alarmRoleArn("arn:aws:iam::520900602629:role/MyAppConfigAlarmRole").build())
        );

        // Start a deployment
        StartDeploymentResponse deploymentResponse = appconfig.startDeployment(req -> req
            .applicationId(app.id())
            .configurationProfileId(configProfile.id())
            .environmentId(env.id())
            .configurationVersion(hcv.versionNumber().toString())
            .deploymentStrategyId("AppConfig.Linear50PercentEvery30Seconds")
        );

        // Wait for deployment to complete
        List<DeploymentState> nonFinalDeploymentStates = Arrays.asList(
            DeploymentState.DEPLOYING,
            DeploymentState.BAKING,
            DeploymentState.ROLLING_BACK,
            DeploymentState.VALIDATING);
        GetDeploymentRequest getDeploymentRequest = GetDeploymentRequest.builder().applicationId(app.id())
                                                                        .environmentId(env.id())
                                                                        .deploymentNumber(deploymentResponse.deploymentNumber()).build();
        GetDeploymentResponse deployment = appconfig.getDeployment(getDeploymentRequest);
        while (nonFinalDeploymentStates.contains(deployment.state())) {
            System.out.println("Waiting for deployment to complete: " + deployment);
            Thread.sleep(1000L);
            deployment = appconfig.getDeployment(getDeploymentRequest);
        }

        System.out.println("Deployment complete: " + deployment);
    }
```

------
#### [ Python ]

```
import boto3

appconfig = boto3.client('appconfig')

# create an application
application = appconfig.create_application(Name='MyDemoApp')

# create an environment
environment = appconfig.create_environment(
    ApplicationId=application['Id'],
    Name='MyEnvironment')

# create a configuration profile
config_profile = appconfig.create_configuration_profile(
    ApplicationId=application['Id'],
    Name='MyConfigProfile',
    LocationUri='hosted',
    Type='AWS.Freeform')

# create a hosted configuration version
hcv = appconfig.create_hosted_configuration_version(
    ApplicationId=application['Id'], 
    ConfigurationProfileId=config_profile['Id'],
    Content=b'my config data',
    ContentType='text/plain')

# start a deployment
deployment = appconfig.start_deployment(
    ApplicationId=application['Id'],
    EnvironmentId=environment['Id'],
    ConfigurationProfileId=config_profile['Id'],
    ConfigurationVersion=str(hcv['VersionNumber']),
    DeploymentStrategyId='AppConfig.Linear20PercentEvery6Minutes')
```

------
#### [ JavaScript ]

```
import {
  AppConfigClient,
  CreateApplicationCommand,
  CreateEnvironmentCommand,
  CreateConfigurationProfileCommand,
  CreateHostedConfigurationVersionCommand,
  StartDeploymentCommand,
} from "@aws-sdk/client-appconfig";

const appconfig = new AppConfigClient();

// create an application
const application = await appconfig.send(
  new CreateApplicationCommand({ Name: "MyDemoApp" })
);

// create an environment
const environment = await appconfig.send(
  new CreateEnvironmentCommand({
    ApplicationId: application.Id,
    Name: "MyEnvironment",
  })
);

// create a configuration profile
const config_profile = await appconfig.send(
  new CreateConfigurationProfileCommand({
    ApplicationId: application.Id,
    Name: "MyConfigProfile",
    LocationUri: "hosted",
    Type: "AWS.Freeform",
  })
);

// create a hosted configuration version
const hcv = await appconfig.send(
  new CreateHostedConfigurationVersionCommand({
    ApplicationId: application.Id,
    ConfigurationProfileId: config_profile.Id,
    Content: "my config data",
    ContentType: "text/plain",
  })
);

// start a deployment
await appconfig.send(
  new StartDeploymentCommand({
    ApplicationId: application.Id,
    EnvironmentId: environment.Id,
    ConfigurationProfileId: config_profile.Id,
    ConfigurationVersion: hcv.VersionNumber.toString(),
    DeploymentStrategyId: "AppConfig.Linear20PercentEvery6Minutes",
  })
);
```

------

# Using AWS AppConfig Agent to read a freeform configuration profile


Each of the following samples includes comments about the actions performed by the code. 

------
#### [ Java ]

```
public void retrieveConfigFromAgent() throws Exception {
        /*
        In this sample, we will retrieve configuration data from the AWS AppConfig Agent.
        The agent is a sidecar process that handles retrieving configuration data from AppConfig
        for you in a way that implements best practices like configuration caching.

        For more information about the agent, see [How to use AWS AppConfig Agent](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-agent-how-to-use.html)
        */

        // The agent runs a local HTTP server that serves configuration data
        // Make a GET request to the agent's local server to retrieve the configuration data
        URL url = new URL("http://localhost:2772/applications/MyDemoApp/environments/Beta/configurations/MyConfigProfile");
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setRequestMethod("GET");
        // To enable entity-based deployments, add the Entity-Id header to the request:
        // con.setRequestProperty("Entity-Id", entityId);
        StringBuilder content;
        try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
            content = new StringBuilder();
            int ch;
            while ((ch = in.read()) != -1) {
                content.append((char) ch);
            }
        }
        con.disconnect();
        System.out.println("Configuration from agent via HTTP: " + content);
    }
```

------
#### [ Python ]

```
# in this sample, we will retrieve configuration data from the AWS AppConfig Agent.
# the agent is a sidecar process that handles retrieving configuration data from AWS AppConfig
# for you in a way that implements best practices like configuration caching.
# 
# for more information about the agent, see
# [How to use AWS AppConfig Agent](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-agent-how-to-use.html)
# 

import requests

application_name = 'MyDemoApp'
environment_name = 'MyEnvironment'
config_profile_name = 'MyConfigProfile'

# To enable entity-based deployments, add the Entity-Id header to the request:
# response = requests.get(f"http://localhost:2772/applications/{application_name}/environments/{environment_name}/configurations/{config_profile_name}",
#                         headers={"Entity-Id": entity_id})
# the agent runs a local HTTP server that serves configuration data
# make a GET request to the agent's local server to retrieve the configuration data
response = requests.get(f"http://localhost:2772/applications/{application_name}/environments/{environment_name}/configurations/{config_profile_name}") 
config = response.content
```

------
#### [ JavaScript ]

```
// in this sample, we will retrieve configuration data from the AWS AppConfig Agent.
// the agent is a sidecar process that handles retrieving configuration data from AppConfig
// for you in a way that implements best practices like configuration caching.

// for more information about the agent, see
// [How to use AWS AppConfig Agent](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-agent-how-to-use.html)

const application_name = "MyDemoApp";
const environment_name = "MyEnvironment";
const config_profile_name = "MyConfigProfile";

// the agent runs a local HTTP server that serves configuration data
// make a GET request to the agent's local server to retrieve the configuration data
const url = `http://localhost:2772/applications/${application_name}/environments/${environment_name}/configurations/${config_profile_name}`;
// To enable entity-based deployments, add the Entity-Id header to the request:
// const response = await fetch(url, { headers: { "Entity-Id": entityId } });
const response = await fetch(url);
const config = await response.text(); // (use `await response.json()` if your config is json)
```

------

# Using AWS AppConfig Agent to read a specific feature flag


Each of the following samples includes comments about the actions performed by the code.

------
#### [ Java ]

```
public void retrieveSingleFlagFromAgent() throws Exception {
        /*
          You can retrieve a single flag's data from the agent by providing the "flag" query string parameter.
          Note: the configuration's type must be AWS.AppConfig.FeatureFlags
        */

        URL url = new URL("http://localhost:2772/applications/MyDemoApp/environments/Beta/configurations/MyFlagsProfile?flag=myFlagKey");
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setRequestMethod("GET");
        StringBuilder content;
        try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
            content = new StringBuilder();
            int ch;
            while ((ch = in.read()) != -1) {
                content.append((char) ch);
            }
        }
        con.disconnect();
        System.out.println("MyFlagName from agent: " + content);
    }
```

------
#### [ Python ]

```
import requests

application_name = 'MyDemoApp'
environment_name = 'MyEnvironment'
config_profile_name = 'MyConfigProfile'
flag_key = 'MyFlag'

# retrieve a single flag's data by providing the "flag" query string parameter
# note: the configuration's type must be AWS.AppConfig.FeatureFlags
response = requests.get(f"http://localhost:2772/applications/{application_name}/environments/{environment_name}/configurations/{config_profile_name}?flag={flag_key}") 
config = response.content
```

------
#### [ JavaScript ]

```
const application_name = "MyDemoApp";
const environment_name = "MyEnvironment";
const config_profile_name = "MyConfigProfile";
const flag_name = "MyFlag";

// retrieve a single flag's data by providing the "flag" query string parameter
// note: the configuration's type must be AWS.AppConfig.FeatureFlags
const url = `http://localhost:2772/applications/${application_name}/environments/${environment_name}/configurations/${config_profile_name}?flag=${flag_name}`;
const response = await fetch(url);
const flag = await response.json(); // { "enabled": true/false }
```

------

# Using AWS AppConfig Agent to retrieve a feature flag with variants


Each of the following samples includes comments about the actions performed by the code.

------
#### [ Java ]

```
public static void retrieveConfigFromAgentWithVariants() throws Exception {
    /*
    This sample retrieves feature flag configuration data 
    containing variants from AWS AppConfig Agent.

    For more information about the agent, see [How to use AWS AppConfig Agent](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-agent-how-to-use.html)
    */

    // Make a GET request to the agent's local server to retrieve the configuration data
    URL url = new URL("http://localhost:2772/applications/MyDemoApp/environments/Beta/configurations/MyConfigProfile");
    HttpURLConnection con = (HttpURLConnection) url.openConnection();

    // Provide context in the 'Context' header
    // In the header value, use '=' to separate context key from context value
    // Note: Multiple context values may be passed either across 
    // multiple headers or as comma-separated values in a single header
    con.setRequestProperty("Context", "country=US");

    StringBuilder content;
    try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
        content = new StringBuilder();
        int ch;
        while ((ch = in.read()) != -1) {
            content.append((char) ch);
        }
    }
    con.disconnect();
    System.out.println("Configuration from agent via HTTP: " + content);
}
```

------
#### [ Python ]

```
# This sample retrieve features flag configuration data 
# containing variants from AWS AppConfig Agent.

# For more information about the agent, see [How to use AWS AppConfig Agent](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-agent-how-to-use.html)

import requests

application_name = 'MyDemoApp'
environment_name = 'Beta'
configuration_profile_name = 'MyConfigProfile'

# make a GET request to the agent's local server to retrieve the configuration data
response = requests.get(f"http://localhost:2772/applications/{application_name}/environments/{environment_name}/configurations/{configuration_profile_name}",
                        headers = {
                            "Context": "country=US" # Provide context in the 'Context' header
                                                    # In the header value, use '=' to separate context key from context value
                                                    # Note: Multiple context values may be passed either across 
                                                    # multiple headers or as comma-separated values in a single header
                        }
)
print("Configuration from agent via HTTP: ", response.json())
```

------
#### [ JavaScript ]

```
// This sample retrieves feature flag configuration data 
// containing variants from AWS AppConfig Agent.

// For more information about the agent, see [How to use AWS AppConfig Agent](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-agent-how-to-use.html)

const application_name = "MyDemoApp";
const environment_name = "Beta";
const configuration_profile_name = "MyConfigProfile";

const url = `http://localhost:2772/applications/${application_name}/environments/${environment_name}/configurations/${configuration_profile_name}`;

// make a GET request to the agent's local server to retrieve the configuration data
const response = await fetch(url, {
    method: 'GET',
    headers: {
        'Context': 'country=US' // Provide context in the 'Context' header
                                // In the header value, use '=' to separate context key from context value
                                // Note: Multiple context values may be passed either across 
                                // multiple headers or as comma-separated values in a single header
    }
});

const config = await response.json();
console.log("Configuration from agent via HTTP: ", config);
```

------

# Using the GetLatestConfiguration API action to read a freeform configuration profile


Each of the following samples includes comments about the actions performed by the code. The samples in this section call the following APIs:
+ [GetLatestConfiguration](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_GetLatestConfiguration.html)
+ [StartConfigurationSession](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_StartConfigurationSession.html)

------
#### [ Java ]

```
/*
The example below uses two AWS AppConfig Data APIs: StartConfigurationSession and GetLatestConfiguration.
For more information about these APIs, see [AWS AppConfig Data](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_Operations_AWS_AppConfig_Data.html).

This class is meant to be used as a singleton to retrieve the latest configuration data from AWS AppConfig.
This class maintains a cache of the latest configuration data in addition to the configuration token to be
passed to the next GetLatestConfiguration API call.
*/
public class AppConfigApiRetriever {

    /*
     * Set of AppConfig invalid parameter problems that require restarting the configuration session.
     * If the GetLatestConfiguration API call fails with any of these problems (e.g. token is EXPIRED or CORRUPTED),
     * we need to call StartConfigurationSession again to obtain a new configuration token before retrying.
     */
    private final Set<InvalidParameterProblem> SESSION_RESTART_REQUIRED =
            Stream.of(InvalidParameterProblem.EXPIRED, InvalidParameterProblem.CORRUPTED)
                  .collect(Collectors.toSet());

    /*
    AWS AppConfig Data SDK client used to interact with the AWS AppConfig Data service.
     */
    private final AppConfigDataClient appConfigData;

    /*
    The configuration token to be passed to the next GetLatestConfiguration API call.
     */
    private String configurationToken;

    /*
    The cached configuration data to be returned when there is no new configuration data available.
     */
    private SdkBytes configuration;

    public AppConfigApiRetriever() {
        this.appConfigData = AppConfigDataClient.create();
    }

    /*
    Returns the latest configuration data stored in AWS AppConfig.
     */
    public SdkBytes getConfig() {
        /*
        If there is no configuration token yet, get one by starting a new session with the StartConfigurationSession API.
        Note that this API does not return configuration data. Rather, it returns an initial configuration token that is
        subsequently passed to the GetLatestConfiguration API.
         */
        if (this.configurationToken == null) {
            startNewSession();
        }

        GetLatestConfigurationResponse response = null;

        try {
            /*
            Retrieve the configuration from the GetLatestConfiguration API, providing the current configuration token.
            If this caller does not yet have the latest configuration (e.g. this is the first call to GetLatestConfiguration
            or new configuration data has been deployed since the first call), the latest configuration data will be returned.
            Otherwise, the GetLatestConfiguration API will not return any data since the caller already has the latest.
             */
            response = appConfigData.getLatestConfiguration(
                    GetLatestConfigurationRequest.builder()
                                                 .configurationToken(this.configurationToken)
                                                 .build());

        } catch (ResourceNotFoundException e) {
            // Handle resource not found by refreshing the session
            System.err.println("Resource not found — refreshing session and retrying...");
            startNewSession();
            response = appConfigData.getLatestConfiguration(
                    GetLatestConfigurationRequest.builder()
                                                 .configurationToken(this.configurationToken)
                                                 .build());
        } catch (BadRequestException e) {
            // Handle expired or corrupted token by refreshing the session
            boolean needsNewSession = Optional.ofNullable(e.details())
                                              .map(details -> details.invalidParameters()
                                                                     .values()
                                                                     .stream()
                                                                     .anyMatch(val -> SESSION_RESTART_REQUIRED.contains(val.problem())))
                                              .orElse(false);
            if (needsNewSession) {
                System.err.println("Configuration token expired or corrupted — refreshing session and retrying...");
                startNewSession();
                response = appConfigData.getLatestConfiguration(
                        GetLatestConfigurationRequest.builder()
                                                     .configurationToken(this.configurationToken)
                                                     .build());
            } else {
                throw e; // rethrow if it's another kind of bad request
            }
        }

        if (response == null) {
            // Should not happen, but return cached config if no response
            return this.configuration;
        }

        /*
        Save the returned configuration token so that it can be passed to the next GetLatestConfiguration API call.
        Warning: Not persisting this token for use in the next GetLatestConfiguration API call may result in higher
        than expected usage costs.
         */
        this.configurationToken = response.nextPollConfigurationToken();

        /*
        If the GetLatestConfiguration API returned configuration data, update the cached configuration with the returned data.
        Otherwise, assume the configuration has not changed, and return the cached configuration.
         */
        SdkBytes configFromApi = response.configuration();
        if (configFromApi != null && configFromApi.asByteArray().length != 0) {
            this.configuration = configFromApi;
            System.out.println("Configuration contents have changed since the last GetLatestConfiguration call, new contents = "
                    + this.configuration.asUtf8String());
        } else {
            System.out.println("GetLatestConfiguration returned an empty response because we already have the latest configuration");
        }

        return this.configuration;
    }

    /*
    Starts a new session with AppConfig and retrieves an initial configuration token.
     */
    private void startNewSession() {
        StartConfigurationSessionResponse session = appConfigData.startConfigurationSession(req -> req
                .applicationIdentifier("MyDemoApp")
                .configurationProfileIdentifier("MyConfig")
                .environmentIdentifier("Beta"));
        this.configurationToken = session.initialConfigurationToken();
    }
}
```

------
#### [ Python ]

```
# The example below uses two AWS AppConfig Data APIs: StartConfigurationSession and GetLatestConfiguration.
# For more information about these APIs, see [AWS AppConfig Data](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_Operations_AWS_AppConfig_Data.html).
#
# This class is meant to be used as a singleton to retrieve the latest configuration data from AWS AppConfig.
# This class maintains a cache of the latest configuration data in addition to the configuration token to be
# passed to the next GetLatestConfiguration API call.
class AppConfigApiRetriever:
    # Set of AppConfig invalid parameter problems that require restarting the configuration session.
    # If the GetLatestConfiguration API call fails with any of these problems (e.g. token is EXPIRED or CORRUPTED),
    # we need to call StartConfigurationSession again to obtain a new configuration token before retrying.
    SESSION_RESTART_REQUIRED = {"EXPIRED", "CORRUPTED"}

    def __init__(self):
        # AWS AppConfig Data SDK client used to interact with the AWS AppConfig Data service.
        self.appconfigdata = boto3.client('appconfigdata')

        # The configuration token to be passed to the next GetLatestConfiguration API call.
        self.configuration_token = None

        # The cached configuration data to be returned when there is no new configuration data available.
        self.configuration = None

    # Returns the latest configuration data stored in AWS AppConfig.
    def get_config(self):
        # If there is no configuration token yet, get one by starting a new session with the StartConfigurationSession API.
        # Note that this API does not return configuration data. Rather, it returns an initial configuration token that is
        # subsequently passed to the GetLatestConfiguration API.
        if not self.configuration_token:
            self._start_new_session()

        response = None
        try:
            # Retrieve the configuration from the GetLatestConfiguration API, providing the current configuration token.
            # If this caller does not yet have the latest configuration (e.g. this is the first call to GetLatestConfiguration
            # or new configuration data has been deployed since the first call), the latest configuration data will be returned.
            # Otherwise, the GetLatestConfiguration API will not return any data since the caller already has the latest.
            response = self.appconfigdata.get_latest_configuration(
                ConfigurationToken=self.configuration_token
            )
        except ClientError as e:
            error_code = e.response.get("Error", {}).get("Code")
            # ResourceNotFoundException — usually means the token/session is invalid or expired
            if error_code == "ResourceNotFoundException":
                print("Resource not found — refreshing session and retrying...")
                self._start_new_session()
                response = self.appconfigdata.get_latest_configuration(
                    ConfigurationToken=self.configuration_token
                )
            # BadRequestException — check if it's expired or corrupted token
            elif error_code == "BadRequestException":
                details = e.response.get("Error", {}).get("Details", {}) or {}
                invalid_params = details.get("InvalidParameters", {}) or {}
                needs_new_session = any(
                    param.get("Problem") in self.SESSION_RESTART_REQUIRED
                    for param in invalid_params.values()
                )
                if needs_new_session:
                    print("Configuration token expired or corrupted — refreshing session and retrying...")
                    self._start_new_session()
                    response = self.appconfigdata.get_latest_configuration(
                        ConfigurationToken=self.configuration_token
                    )
                else:
                    raise
            else:
                raise

        if response is None:
            # Should not happen, but return cached config if no response
            return self.configuration

        # Save the returned configuration token so that it can be passed to the next GetLatestConfiguration API call.
        # Warning: Not persisting this token for use in the next GetLatestConfiguration API call may result in higher
        # than expected usage costs.
        self.configuration_token = response['NextPollConfigurationToken']

        # If the GetLatestConfiguration API returned configuration data, update the cached configuration with the returned data.
        # Otherwise, assume the configuration has not changed, and return the cached configuration.
        config_stream = response.get('Configuration')
        if config_stream:
            config_from_api = config_stream.read()
            if config_from_api:
                self.configuration = config_from_api
                print(
                    'Configuration contents have changed since the last GetLatestConfiguration call, new contents = '
                    + self.configuration.decode('utf-8', errors='ignore')
                )
            else:
                print('GetLatestConfiguration returned an empty response because we already have the latest configuration')

        return self.configuration

    # Starts a new session with AppConfig and retrieves an initial configuration token.
    def _start_new_session(self):
        session = self.appconfigdata.start_configuration_session(
            ApplicationIdentifier='MyDemoApp',
            ConfigurationProfileIdentifier='MyConfig',
            EnvironmentIdentifier='Beta'
        )
        self.configuration_token = session['InitialConfigurationToken']
```

------
#### [ JavaScript ]

```
/*
The example below uses two AWS AppConfig Data APIs: StartConfigurationSession and GetLatestConfiguration.
For more information about these APIs, see [AWS AppConfig Data](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_Operations_AWS_AppConfig_Data.html)
.

This class is meant to be used as a singleton to retrieve the latest configuration data from AWS AppConfig.
This class maintains a cache of the latest configuration data in addition to the configuration token to be
passed to the next GetLatestConfiguration API call.
*/
class AppConfigApiRetriever {
  constructor() {
    /*
    AWS AppConfig Data SDK client used to interact with the AWS AppConfig Data service.
     */
    this.appconfigdata = new AppConfigDataClient();

    /*
    The configuration token to be passed to the next GetLatestConfiguration API call.
     */
    this.configurationToken = null;

    /*
    The cached configuration data to be returned when there is no new configuration data available.
     */
    this.configuration = null;
  }

  async startSession() {
    /*
    Starts a new session with the StartConfigurationSession API to get an initial configuration token.
    */
    const session = await this.appconfigdata.send(
      new StartConfigurationSessionCommand({
        ApplicationIdentifier: "MyDemoApp",
        ConfigurationProfileIdentifier: "MyConfig",
        EnvironmentIdentifier: "Beta"
      })
    );
    this.configurationToken = session.InitialConfigurationToken;
  }

  /*
  Returns the latest configuration data stored in AWS AppConfig.
   */
  async getConfig() {
    /*
    If there is no configuration token yet, get one by starting a new session with the StartConfigurationSession API.
    Note that this API does not return configuration data. Rather, it returns an initial configuration token that is
    subsequently passed to the GetLatestConfiguration API.
    */
    if (!this.configurationToken) {
      await this.startSession();
    }

    let response;
    try {
      /*
      Retrieve the configuration from the GetLatestConfiguration API, providing the current configuration token.
      If this caller does not yet have the latest configuration (e.g. this is the first call to GetLatestConfiguration
      or new configuration data has been deployed since the first call), the latest configuration data will be returned.
      Otherwise, the GetLatestConfiguration API will not return any data since the caller already has the latest.
      */
      response = await this.appconfigdata.send(
        new GetLatestConfigurationCommand({
          ConfigurationToken: this.configurationToken
        })
      );
    } catch (err) {
      /*
      Add session restart logic — if the token is invalid or expired, restart the session and try once more.
      */
      if (err.name === "ResourceNotFoundException" || err.name === "BadRequestException") {
        console.warn(
          "Configuration token invalid or expired. Restarting session..."
        );
        await this.startSession();
        response = await this.appconfigdata.send(
          new GetLatestConfigurationCommand({
            ConfigurationToken: this.configurationToken
          })
        );
      } else {
        throw err;
      }
    }

    /*
    Save the returned configuration token so that it can be passed to the next GetLatestConfiguration API call.
    Warning: Not persisting this token for use in the next GetLatestConfiguration API call may result in higher
    than expected usage costs.
    */
    this.configurationToken = response.NextPollConfigurationToken;

    /*
    If the GetLatestConfiguration API returned configuration data, update the cached configuration with the returned data.
    Otherwise, assume the configuration has not changed, and return the cached configuration.
    */
    const configFromApi = response.Configuration
      ? await response.Configuration.transformToString()
      : null;

    if (configFromApi) {
      this.configuration = configFromApi;
      console.log(
        "Configuration contents have changed since the last GetLatestConfiguration call, new contents = " +
          this.configuration
      );
    } else {
      console.log(
        "GetLatestConfiguration returned an empty response because we already have the latest configuration"
      );
    }

    return this.configuration;
  }
}
```

------

# Cleaning up your environment


If you ran one or more of the code samples in this section, we recommend you use one of the following samples to locate and delete the AWS AppConfig resources created by those code samples. The samples in this section call the following APIs:
+ [ListApplications](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_ListApplications.html)
+ [DeleteApplication](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_DeleteApplication.html)
+ [ListEnvironments](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_ListEnvironments.html)
+ [DeleteEnvironments](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_DeleteEnvironment.html)
+ [ListConfigurationProfiles](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_ListConfigurationProfiles.html)
+ [DeleteConfigurationProfile](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_DeleteConfigurationProfile.html)
+ [ListHostedConfigurationVersions](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_ListHostedConfigurationVersions.html)
+ [DeleteHostedConfigurationVersion](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_DeleteHostedConfigurationVersion.html)

------
#### [ Java ]

```
/*
    This sample provides cleanup code that deletes all the AWS AppConfig resources created in the samples above.

    WARNING: this code will permanently delete the given application and all of its sub-resources, including
    configuration profiles, hosted configuration versions, and environments. DO NOT run this code against
    an application that you may need in the future.
    */
    
    public void cleanUpDemoResources() {
        AppConfigClient appconfig = AppConfigClient.create();
        
        // The name of the application to delete
        // IMPORTANT: verify this name corresponds to the application you wish to delete
        String applicationToDelete = "MyDemoApp";
        
        appconfig.listApplicationsPaginator(ListApplicationsRequest.builder().build()).items().forEach(app -> {
            if (app.name().equals(applicationToDelete)) {
                System.out.println("Deleting App: " + app);
                appconfig.listConfigurationProfilesPaginator(req -> req.applicationId(app.id())).items().forEach(cp -> {
                    System.out.println("Deleting Profile: " + cp);
                    appconfig
                        .listHostedConfigurationVersionsPaginator(req -> req
                            .applicationId(app.id())
                            .configurationProfileId(cp.id()))
                        .items()
                        .forEach(hcv -> {
                            System.out.println("Deleting HCV: " + hcv);
                            appconfig.deleteHostedConfigurationVersion(req -> req
                                .applicationId(app.id())
                                .configurationProfileId(cp.id())
                                .versionNumber(hcv.versionNumber()));
                        });
                    appconfig.deleteConfigurationProfile(req -> req
                        .applicationId(app.id())
                        .configurationProfileId(cp.id()));
                });

                appconfig.listEnvironmentsPaginator(req->req.applicationId(app.id())).items().forEach(env -> {
                    System.out.println("Deleting Environment: " + env);
                    appconfig.deleteEnvironment(req->req.applicationId(app.id()).environmentId(env.id()));
                });

                appconfig.deleteApplication(req -> req.applicationId(app.id()));
            }
        });
    }
```

------
#### [ Python ]

```
# this sample provides cleanup code that deletes all the AWS AppConfig resources created in the samples above.
#
# WARNING: this code will permanently delete the given application and all of its sub-resources, including
#   configuration profiles, hosted configuration versions, and environments. DO NOT run this code against
#   an application that you may need in the future.
#

import boto3 

# the name of the application to delete
# IMPORTANT: verify this name corresponds to the application you wish to delete
application_name = 'MyDemoApp'

# create and iterate over a list paginator such that we end up with a list of pages, which are themselves lists of applications
# e.g. [ [{'Name':'MyApp1',...},{'Name':'MyApp2',...}], [{'Name':'MyApp3',...}] ]
list_of_app_lists = [page['Items'] for page in appconfig.get_paginator('list_applications').paginate()]
# retrieve the target application from the list of lists
application = [app for apps in list_of_app_lists for app in apps if app['Name'] == application_name][0]
print(f"deleting application {application['Name']} (id={application['Id']})")

# delete all configuration profiles
list_of_config_lists = [page['Items'] for page in appconfig.get_paginator('list_configuration_profiles').paginate(ApplicationId=application['Id'])]
for config_profile in [config for configs in list_of_config_lists for config in configs]:
    print(f"\tdeleting configuration profile {config_profile['Name']} (Id={config_profile['Id']})")

    # delete all hosted configuration versions
    list_of_hcv_lists = [page['Items'] for page in appconfig.get_paginator('list_hosted_configuration_versions').paginate(ApplicationId=application['Id'], ConfigurationProfileId=config_profile['Id'])]
    for hcv in [hcv for hcvs in list_of_hcv_lists for hcv in hcvs]:
        appconfig.delete_hosted_configuration_version(ApplicationId=application['Id'], ConfigurationProfileId=config_profile['Id'], VersionNumber=hcv['VersionNumber'])
        print(f"\t\tdeleted hosted configuration version {hcv['VersionNumber']}")

    # delete the config profile itself
    appconfig.delete_configuration_profile(ApplicationId=application['Id'], ConfigurationProfileId=config_profile['Id'])
    print(f"\tdeleted configuration profile {config_profile['Name']} (Id={config_profile['Id']})")

# delete all environments
list_of_env_lists = [page['Items'] for page in appconfig.get_paginator('list_environments').paginate(ApplicationId=application['Id'])]
for environment in [env for envs in list_of_env_lists for env in envs]:
    appconfig.delete_environment(ApplicationId=application['Id'], EnvironmentId=environment['Id'])
    print(f"\tdeleted environment {environment['Name']} (Id={environment['Id']})")

# delete the application itself
appconfig.delete_application(ApplicationId=application['Id'])
print(f"deleted application {application['Name']} (id={application['Id']})")
```

------
#### [ JavaScript ]

```
// this sample provides cleanup code that deletes all the AWS AppConfig resources created in the samples above.

// WARNING: this code will permanently delete the given application and all of its sub-resources, including
//   configuration profiles, hosted configuration versions, and environments. DO NOT run this code against
//   an application that you may need in the future.

import {
  AppConfigClient,
  paginateListApplications,
  DeleteApplicationCommand,
  paginateListConfigurationProfiles,
  DeleteConfigurationProfileCommand,
  paginateListHostedConfigurationVersions,
  DeleteHostedConfigurationVersionCommand,
  paginateListEnvironments,
  DeleteEnvironmentCommand,
} from "@aws-sdk/client-appconfig";

const client = new AppConfigClient();

// the name of the application to delete
// IMPORTANT: verify this name corresponds to the application you wish to delete
const application_name = "MyDemoApp";

// iterate over all applications, deleting ones that have the name defined above
for await (const app_page of paginateListApplications({ client }, {})) {
  for (const application of app_page.Items) {

    // skip applications that dont have the name thats set
    if (application.Name !== application_name) continue;

    console.log( `deleting application ${application.Name} (id=${application.Id})`);

    // delete all configuration profiles
    for await (const config_page of paginateListConfigurationProfiles({ client }, { ApplicationId: application.Id })) {
      for (const config_profile of config_page.Items) {
        console.log(`\tdeleting configuration profile ${config_profile.Name} (Id=${config_profile.Id})`);

        // delete all hosted configuration versions
        for await (const hosted_page of paginateListHostedConfigurationVersions({ client },
          { ApplicationId: application.Id, ConfigurationProfileId: config_profile.Id }
        )) {
          for (const hosted_config_version of hosted_page.Items) {
            await client.send(
              new DeleteHostedConfigurationVersionCommand({
                ApplicationId: application.Id,
                ConfigurationProfileId: config_profile.Id,
                VersionNumber: hosted_config_version.VersionNumber,
              })
            );
            console.log(`\t\tdeleted hosted configuration version ${hosted_config_version.VersionNumber}`);
          }
        }

        // delete the config profile itself
        await client.send(
          new DeleteConfigurationProfileCommand({
            ApplicationId: application.Id,
            ConfigurationProfileId: config_profile.Id,
          })
        );
        console.log(`\tdeleted configuration profile ${config_profile.Name} (Id=${config_profile.Id})`)
      }

      // delete all environments
      for await (const env_page of paginateListEnvironments({ client }, { ApplicationId: application.Id })) {
        for (const environment of env_page.Items) {
          await client.send(
            new DeleteEnvironmentCommand({
              ApplicationId: application.Id,
              EnvironmentId: environment.Id,
            })
          );
          console.log(`\tdeleted environment ${environment.Name} (Id=${environment.Id})`)
        }
      }
    }

    // delete the application itself
    await client.send(
      new DeleteApplicationCommand({ ApplicationId: application.Id })
    );
    console.log(`deleted application ${application.Name} (id=${application.Id})`)
  }
}
```

------