Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
224 changes: 159 additions & 65 deletions sdk/appconfiguration/azure-data-appconfiguration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ When an HTTP client is included on the classpath, as shown above, it is not nece

For starters, by having the Netty or OkHTTP dependencies on your classpath, as shown above, you can create new instances of these `HttpClient` types using their builder APIs. For example, here is how you would create a Netty HttpClient instance:

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L37-L40 -->
```java
HttpClient client = new NettyAsyncHttpClientBuilder()
.port(8080)
Expand Down Expand Up @@ -107,7 +108,9 @@ az appconfig create --name <config-store-name> --resource-group <resource-group-

In order to interact with the App Configuration service you'll need to create an instance of the Configuration Client class. To make this possible you'll need the connection string of the Configuration Store.

#### Get credentials
#### Use connection string

##### Get credentials

Use the [Azure CLI][azure_cli] snippet below to get the connection string from the Configuration Store.

Expand All @@ -117,37 +120,82 @@ az appconfig credential list --name <config-store-name>

Alternatively, get the connection string from the Azure Portal.

#### Create a Configuration Client
##### Create a Configuration Client

Once you have the value of the connection string you can create the configuration client:

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L44-L46 -->
```Java
ConfigurationClient client = new ConfigurationClientBuilder()
.connectionString(connectionString)
.buildClient();
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
.connectionString(connectionString)
.buildClient();
```

or

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L50-L52 -->
```Java
ConfigurationAsyncClient client = new ConfigurationClientBuilder()
.connectionString(connectionString)
.buildAsyncClient();
ConfigurationAsyncClient configurationClient = new ConfigurationClientBuilder()
.connectionString(connectionString)
.buildAsyncClient();
```

You can also use `TokenCredential` to create a configuration client, such as an Azure Active Directory (AAD) token.
Unlike a connection string if you're using an AAD token you must supply the endpoint of AppConfiguration service. The
endpoint can be obtained by going to your App Configuration instance in the Azure portal and navigating to "Overview"
page and look for the "Endpoint" keyword.
#### Use AAD token

```Java
// An example of using TokenCredential and Endpoint to create a synchronous client
TokenCredential credential = new DefaultAzureCredential();
Here we demonstrate using [DefaultAzureCredential][default_cred_ref]
to authenticate as a service principal. However, the configuration client
accepts any [azure-identity][azure_identity] credential. See the
[azure-identity][azure_identity] documentation for more information about other
credentials.

##### Create a service principal (optional)
This [Azure CLI][azure_cli] snippet shows how to create a
new service principal. Before using it, replace "your-application-name" with
the appropriate name for your service principal.

Create a service principal:
```Bash
az ad sp create-for-rbac --name http://my-application --skip-assignment
```

Output:
```json
{
"appId": "generated app id",
"displayName": "my-application",
"name": "http://my-application",
"password": "random password",
"tenant": "tenant id"
}
```

Use the output to set **AZURE_CLIENT_ID** ("appId" above), **AZURE_CLIENT_SECRET**
("password" above) and **AZURE_TENANT_ID** ("tenant" above) environment variables.
The following example shows a way to do this in Bash:
```Bash
export AZURE_CLIENT_ID="generated app id"
export AZURE_CLIENT_SECRET="random password"
export AZURE_TENANT_ID="tenant id"
```

ConfigurationClient client = new ConfigurationClientBuilder()
.credential(credential)
.endpoint(endpoint)
.buildClient();
Assign one of the applicable [App Configuration roles][app_config_role] to the service principal.

##### Create a client
Once the **AZURE_CLIENT_ID**, **AZURE_CLIENT_SECRET** and
**AZURE_TENANT_ID** environment variables are set,
[DefaultAzureCredential][default_cred_ref] will be able to authenticate the
configuration client.

Constructing the client also requires your configuration store's URL, which you can
get from the Azure CLI or the Azure Portal. In the Azure Portal, the URL can be found listed as the service "Endpoint"

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L56-L60 -->
```Java
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
.credential(credential)
.endpoint(endpoint)
.buildClient();
```

## Key concepts
Expand All @@ -164,30 +212,39 @@ The client performs the interactions with the App Configuration service, getting

An application that needs to retrieve startup configurations is better suited using the synchronous client, for example setting up a SQL connection.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L64-L83 -->
```Java
ConfigurationClient client = new ConfigurationClientBuilder()
.connectionString(connectionString)
.buildClient();
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
.connectionString(connectionString)
.buildClient();

// urlLabel is optional
String url = client.getConfigurationSetting(urlKey, urlLabel).getValue();
Connection conn;
String url = configurationClient.getConfigurationSetting(urlKey, urlLabel).getValue();
Connection conn = null;
try {
conn = DriverManager.getConnection(url);
} catch (SQLException ex) {
System.out.printf("Failed to get connection using url %s", url);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
System.out.printf("Failed to close connection, url %s", url);
}
}
}

```

An application that has a large set of configurations that it needs to periodically update is be better suited using the asynchronous client, for example all settings with a specific label are periodically updated.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L87-L92 -->
```Java
ConfigurationAsyncClient client = new ConfigurationClientBuilder()
.connectionString(appConfigConnectionString)
.buildAsyncClient();
ConfigurationAsyncClient configurationClient = new ConfigurationClientBuilder()
.connectionString(connectionString)
.buildAsyncClient();

client.listConfigurationSettings(new SettingSelector().setLabels(periodicUpdateLabel))
configurationClient.listConfigurationSettings(new SettingSelector().setLabelFilter(periodicUpdateLabel))
.subscribe(setting -> updateConfiguration(setting));
```

Expand All @@ -198,107 +255,140 @@ The following sections provide several code snippets covering some of the most c
### Create a Configuration Client

Create a configuration client by using `ConfigurationClientBuilder` by passing connection string.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L44-L46 -->
```Java
ConfigurationClient client = new ConfigurationClientBuilder()
.connectionString(connectionString)
.buildClient();
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
.connectionString(connectionString)
.buildClient();
```

### Create a Configuration Setting

Create a configuration setting to be stored in the configuration store. There are two ways to store a configuration setting:

- `addConfigurationSetting` creates a setting only if the setting does not already exist in the store.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L96-L96 -->
```Java
ConfigurationSetting setting = configurationClient.addConfigurationSetting("new_key", "new_label", "new_value");
```

Or

- `setConfigurationSetting` creates a setting if it doesn't exist or overrides an existing setting.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L100-L100 -->
```Java
ConfigurationSetting setting = client.setConfigurationSetting("some_key", "some_label", "some_value");
ConfigurationSetting setting = configurationClient.setConfigurationSetting("some_key", "some_label", "some_value");
```

### Retrieve a Configuration Setting

Retrieve a previously stored configuration setting by calling `getConfigurationSetting`.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L104-L105 -->
```Java
ConfigurationSetting setting = client.setConfigurationSetting("some_key", "some_label", "some_value");
ConfigurationSetting retrievedSetting = client.getConfigurationSetting("some_key", "some_label");
ConfigurationSetting setting = configurationClient.setConfigurationSetting("some_key", "some_label", "some_value");
ConfigurationSetting retrievedSetting = configurationClient.getConfigurationSetting("some_key", "some_label");
```

For conditional request, if you want to conditionally fetch a configuration setting, set `ifChanged` to true.
When `ifChanged` is true, the configuration setting is only retrieved if it is different than the given `setting`.
This is determined by comparing the ETag of the `setting` to the one in the service to see if they are the same or not.
If the ETags are not the same, it means the configuration setting is different, and its value is retrieved.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L109-L110 -->
```Java
Response<ConfigurationSetting> settingResponse = client.getConfigurationSettingWithResponse(setting, null, true, Context.NONE);
ConfigurationSetting setting = configurationClient.setConfigurationSetting("some_key", "some_label", "some_value");
Response<ConfigurationSetting> settingResponse = configurationClient.getConfigurationSettingWithResponse(setting, null, true, Context.NONE);
```

### Update an existing Configuration Setting

Update an existing configuration setting by calling `setConfigurationSetting`.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L114-L115 -->
```Java
ConfigurationSetting setting = client.setConfigurationSetting("some_key", "some_label", "some_value");
ConfigurationSetting updatedSetting = client.setConfigurationSetting("some_key", "some_label", "new_value");
ConfigurationSetting setting = configurationClient.setConfigurationSetting("some_key", "some_label", "some_value");
ConfigurationSetting updatedSetting = configurationClient.setConfigurationSetting("some_key", "some_label", "new_value");
```

For conditional request, if you want to conditionally update a configuration setting, set the `ifUnchanged` parameter to
true. When `ifUnchanged` is true, the configuration setting is only updated if it is same as the given `setting`.
This is determined by comparing the ETag of the `setting` to the one in the service to see if they are the same or not.
If the ETag are the same, it means the configuration setting is same, and its value is updated.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L119-L120 -->
```Java
Response<ConfigurationSetting> settingResponse = client.setConfigurationSettingWithResponse(setting, true, Context.NONE);
ConfigurationSetting setting = configurationClient.setConfigurationSetting("some_key", "some_label", "some_value");
Response<ConfigurationSetting> settingResponse = configurationClient.setConfigurationSettingWithResponse(setting, true, Context.NONE);
```

### Delete a Configuration Setting

Delete an existing configuration setting by calling `deleteConfigurationSetting`.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L124-L125 -->
```Java
ConfigurationSetting setting = client.setConfigurationSetting("some_key", "some_label", "some_value");
ConfigurationSetting deletedSetting = client.deleteConfigurationSetting("some_key", "some_label");
ConfigurationSetting setting = configurationClient.setConfigurationSetting("some_key", "some_label", "some_value");
ConfigurationSetting deletedSetting = configurationClient.deleteConfigurationSetting("some_key", "some_label");
```
For conditional request, if you want to conditionally delete a configuration setting, set the `ifUnchanged` parameter
to true. When `ifUnchanged` parameter to true. When `ifUnchanged` is true, the configuration setting is only deleted if
it is same as the given `setting`. This is determined by comparing the ETag of the `setting` to the one in the service
to see if they are the same or not. If the ETag are same, it means the configuration setting is same, and its value is deleted.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L129-L130 -->
```Java
Response<ConfigurationSetting> settingResponse = client.deleteConfigurationSettingWithResponse(setting, true, Context.NONE);
ConfigurationSetting setting = configurationClient.setConfigurationSetting("some_key", "some_label", "some_value");
Response<ConfigurationSetting> settingResponse = configurationClient.deleteConfigurationSettingWithResponse(setting, true, Context.NONE);
```

### List Configuration Settings with multiple keys

List multiple configuration settings by calling `listConfigurationSettings`.
Pass a null `SettingSelector` into the method if you want to fetch all the configuration settings and their fields.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L134-L139 -->
```Java
String key = "some_key";
String key2 = "new_key";
client.setConfigurationSetting(key, "some_label", "some_value");
client.setConfigurationSetting(key2, "new_label", "new_value");
SettingSelector selector = new SettingSelector().setKeys(key, key2);
PagedIterable<ConfigurationSetting> settings = client.listConfigurationSettings(selector);
configurationClient.setConfigurationSetting(key, "some_label", "some_value");
configurationClient.setConfigurationSetting(key2, "new_label", "new_value");
SettingSelector selector = new SettingSelector().setKeyFilter(key + "," + key2);
PagedIterable<ConfigurationSetting> settings = configurationClient.listConfigurationSettings(selector);
```

### List revisions of multiple Configuration Settings

List all revisions of a configuration setting by calling `listRevisions`.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L143-L147 -->
```Java
String key = "revisionKey";
client.setConfigurationSetting(key, "some_label", "some_value");
client.setConfigurationSetting(key, "new_label", "new_value");
SettingSelector selector = new SettingSelector().setKeys(key);
PagedIterable<ConfigurationSetting> settings = client.listRevisions(selector);
configurationClient.setConfigurationSetting(key, "some_label", "some_value");
configurationClient.setConfigurationSetting(key, "new_label", "new_value");
SettingSelector selector = new SettingSelector().setKeyFilter(key);
PagedIterable<ConfigurationSetting> settings = configurationClient.listRevisions(selector);
```

### Set a Configuration Setting to read only

Set a configuration setting to read-only status.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L151-L152 -->
```Java
client.setConfigurationSetting("some_key", "some_label", "some_value");
ConfigurationSetting setting = client.setReadOnly("some_key", "some_label", true);
configurationClient.setConfigurationSetting("some_key", "some_label", "some_value");
ConfigurationSetting setting = configurationClient.setReadOnly("some_key", "some_label", true);
```
### Clear read only from a Configuration Setting

Clear read-only from a configuration setting.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L156-L156 -->
```Java
ConfigurationSetting setting = client.setReadOnly("some_key", "some_label", false);
ConfigurationSetting setting = configurationClient.setReadOnly("some_key", "some_label", false);
```

## Troubleshooting
Expand All @@ -309,17 +399,18 @@ When you interact with App Configuration using this Java client library, errors

App Configuration provides a way to define customized headers through `Context` object in the public API.

<!-- embedme ./src/samples/java/com/azure/data/appconfiguration/ReadmeSamples.java#L160-L169 -->
```java
// Add your headers
HttpHeaders headers = new HttpHeaders();
headers.put("my-header1", "my-header1-value");
headers.put("my-header2", "my-header2-value");
headers.put("my-header3", "my-header3-value");
// Call API by passing headers in Context.
configurationClient.addConfigurationSettingWithResponse(
new ConfigurationSetting().setKey("key").setValue("value"),
new Context(AddHeadersFromContextPolicy.AZURE_REQUEST_HTTP_HEADERS_KEY, headers));
// Above three HttpHeader will be added in outgoing HttpRequest.
// Add your headers
HttpHeaders headers = new HttpHeaders();
headers.put("my-header1", "my-header1-value");
headers.put("my-header2", "my-header2-value");
headers.put("my-header3", "my-header3-value");
// Call API by passing headers in Context.
configurationClient.addConfigurationSettingWithResponse(
new ConfigurationSetting().setKey("key").setValue("value"),
new Context(AddHeadersFromContextPolicy.AZURE_REQUEST_HTTP_HEADERS_KEY, headers));
// Above three HttpHeader will be added in outgoing HttpRequest.
```
For more detail information, check out the [AddHeadersFromContextPolicy][add_headers_from_context_policy]

Expand All @@ -337,23 +428,26 @@ When you submit a pull request, a CLA-bot will automatically determine whether y
This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For more information see the [Code of Conduct FAQ][coc_faq] or contact [[email protected]][coc_contact] with any additional questions or comments.

<!-- LINKS -->
[add_headers_from_context_policy]: https://github.com/Azure/azure-sdk-for-java/blob/master/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AddHeadersFromContextPolicy.java
[api_documentation]: https://aka.ms/java-docs
[app_config_store]: https://docs.microsoft.com/azure/azure-app-configuration/quickstart-dotnet-core-app#create-an-app-configuration-store
[app_config_role]: https://github.com/Azure/AppConfiguration/blob/master/docs/REST/authorization/aad.md
[azconfig_docs]: https://docs.microsoft.com/azure/azure-app-configuration
[azure_cli]: https://docs.microsoft.com/cli/azure
[azure_identity]: https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/identity/azure-identity
[azure_subscription]: https://azure.microsoft.com/free
[cla]: https://cla.microsoft.com
[coc]: https://opensource.microsoft.com/codeofconduct/
[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/
[coc_contact]: mailto:[email protected]
[default_cred_ref]: https://azuresdkdocs.blob.core.windows.net/$web/java/azure-identity/1.0.1/com/azure/identity/DefaultAzureCredential.html
[maven]: https://maven.apache.org/
[package]: https://search.maven.org/artifact/com.azure/azure-data-appconfiguration
[performance_tuning]: https://github.com/Azure/azure-sdk-for-java/wiki/Performance-Tuning
[rest_api]: https://github.com/Azure/AppConfiguration#rest-api-reference
[samples]: src/samples/java/com/azure/data/appconfiguration
[samples_readme]: src/samples/README.md
[source_code]: src
[spring_quickstart]: https://docs.microsoft.com/azure/azure-app-configuration/quickstart-java-spring-app
[performance_tuning]: https://github.com/Azure/azure-sdk-for-java/wiki/Performance-Tuning
[add_headers_from_context_policy]: https://github.com/Azure/azure-sdk-for-java/blob/master/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AddHeadersFromContextPolicy.java

![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-java%2Fsdk%2Fappconfiguration%2Fazure-data-appconfiguration%2FREADME.png)
Loading