diff --git a/sdk/appconfiguration/azure-data-appconfiguration/README.md b/sdk/appconfiguration/azure-data-appconfiguration/README.md index 37fe5789f2d6..52820c3b0f3a 100644 --- a/sdk/appconfiguration/azure-data-appconfiguration/README.md +++ b/sdk/appconfiguration/azure-data-appconfiguration/README.md @@ -307,6 +307,22 @@ ConfigurationSetting setting = client.setReadOnly("some_key", "some_label", fals When you interact with App Configuration using this Java client library, errors returned by the service correspond to the same HTTP status codes returned for [REST API][rest_api] requests. For example, if you try to retrieve a configuration setting that doesn't exist in your configuration store, a `404` error is returned, indicating `Not Found`. +App Configuration provides a way to define customized headers through `Context` object in the public API. + +```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. +``` +For more detail information, check out the [AddHeadersFromContextPolicy][add_headers_from_context_policy] + ## Next steps - Samples are explained in detail [here][samples_readme]. @@ -338,5 +354,6 @@ This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For m [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) diff --git a/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationClientBuilder.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationClientBuilder.java index d4f2533c0a85..af45d4d439e0 100644 --- a/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationClientBuilder.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationClientBuilder.java @@ -10,6 +10,7 @@ import com.azure.core.http.HttpPipeline; import com.azure.core.http.HttpPipelineBuilder; import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.AddHeadersFromContextPolicy; import com.azure.core.http.policy.AddHeadersPolicy; import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; import com.azure.core.http.policy.HttpLogDetailLevel; @@ -179,6 +180,7 @@ public ConfigurationAsyncClient buildAsyncClient() { policies.add(new UserAgentPolicy(httpLogOptions.getApplicationId(), clientName, clientVersion, buildConfiguration)); policies.add(new RequestIdPolicy()); + policies.add(new AddHeadersFromContextPolicy()); policies.add(new AddHeadersPolicy(headers)); policies.add(new AddDatePolicy()); diff --git a/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationAsyncClientTest.java b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationAsyncClientTest.java index f82ea524ac25..5b84281b7234 100644 --- a/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationAsyncClientTest.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationAsyncClientTest.java @@ -2,13 +2,12 @@ // Licensed under the MIT License. package com.azure.data.appconfiguration; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - import com.azure.core.exception.HttpResponseException; import com.azure.core.exception.ResourceExistsException; import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.HttpHeaders; import com.azure.core.http.netty.NettyAsyncHttpClientBuilder; +import com.azure.core.http.policy.AddHeadersFromContextPolicy; import com.azure.core.http.policy.HttpLogDetailLevel; import com.azure.core.http.policy.HttpLogOptions; import com.azure.core.http.policy.RetryPolicy; @@ -23,12 +22,16 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; +import reactor.util.context.Context; import java.net.HttpURLConnection; import java.time.Duration; import java.util.ArrayList; import java.util.List; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + public class ConfigurationAsyncClientTest extends ConfigurationClientTestBase { private final ClientLogger logger = new ClientLogger(ConfigurationAsyncClientTest.class); private static final String NO_LABEL = null; @@ -869,5 +872,18 @@ public void deleteAllSettings() { return client.deleteConfigurationSettingWithResponse(configurationSetting, false); }).blockLast(); } + + @Test + public void addHeadersFromContextPolicyTest() { + final HttpHeaders headers = getCustomizedHeaders(); + addHeadersFromContextPolicyRunner(expected -> + StepVerifier.create(client.addConfigurationSettingWithResponse(expected) + .subscriberContext(Context.of(AddHeadersFromContextPolicy.AZURE_REQUEST_HTTP_HEADERS_KEY, headers))) + .assertNext(response -> { + final HttpHeaders requestHeaders = response.getRequest().getHeaders(); + assertContainsHeaders(headers, requestHeaders); + }) + .verifyComplete()); + } } diff --git a/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTest.java b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTest.java index 07c866d3547c..19037c813a44 100644 --- a/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTest.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTest.java @@ -2,30 +2,32 @@ // Licensed under the MIT License. package com.azure.data.appconfiguration; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - import com.azure.core.exception.HttpResponseException; import com.azure.core.exception.ResourceExistsException; -import com.azure.core.http.netty.NettyAsyncHttpClientBuilder; -import com.azure.core.http.policy.HttpLogOptions; -import com.azure.data.appconfiguration.models.ConfigurationSetting; -import com.azure.data.appconfiguration.models.SettingFields; -import com.azure.data.appconfiguration.models.SettingSelector; import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.netty.NettyAsyncHttpClientBuilder; +import com.azure.core.http.policy.AddHeadersFromContextPolicy; import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; import com.azure.core.http.policy.RetryPolicy; import com.azure.core.http.rest.PagedIterable; +import com.azure.core.http.rest.Response; import com.azure.core.util.Context; import com.azure.core.util.logging.ClientLogger; +import com.azure.data.appconfiguration.models.ConfigurationSetting; +import com.azure.data.appconfiguration.models.SettingFields; +import com.azure.data.appconfiguration.models.SettingSelector; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import java.net.HttpURLConnection; - import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class ConfigurationClientTest extends ConfigurationClientTestBase { private final ClientLogger logger = new ClientLogger(ConfigurationClientTest.class); @@ -644,4 +646,16 @@ public void deleteAllSettings() { client.deleteConfigurationSettingWithResponse(configurationSetting, false, Context.NONE).getValue(); }); } + + @Test + public void addHeadersFromContextPolicyTest() { + final HttpHeaders headers = getCustomizedHeaders(); + addHeadersFromContextPolicyRunner(expected -> { + final Response response = + client.addConfigurationSettingWithResponse(expected, + new Context(AddHeadersFromContextPolicy.AZURE_REQUEST_HTTP_HEADERS_KEY, headers)); + assertContainsHeaders(headers, response.getRequest().getHeaders()); + } + ); + } } diff --git a/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTestBase.java b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTestBase.java index 9360de2315c6..a50b2ded5d8c 100644 --- a/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTestBase.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTestBase.java @@ -2,14 +2,8 @@ // Licensed under the MIT License. package com.azure.data.appconfiguration; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpHeaders; import com.azure.core.http.rest.Response; import com.azure.core.test.TestBase; import com.azure.core.util.Configuration; @@ -19,6 +13,9 @@ import com.azure.data.appconfiguration.models.ConfigurationSetting; import com.azure.data.appconfiguration.models.SettingFields; import com.azure.data.appconfiguration.models.SettingSelector; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + import java.lang.reflect.Field; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -34,8 +31,13 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public abstract class ConfigurationClientTestBase extends TestBase { private static final String AZURE_APPCONFIG_CONNECTION_STRING = "AZURE_APPCONFIG_CONNECTION_STRING"; @@ -379,6 +381,17 @@ void listRevisionsWithMultipleLabelsRunner(String key, String label, String labe @Test public abstract void deleteAllSettings(); + @Test + public abstract void addHeadersFromContextPolicyTest(); + + void addHeadersFromContextPolicyRunner(Consumer testRunner) { + final String key = getKey(); + final String value = "newValue"; + + final ConfigurationSetting newConfiguration = new ConfigurationSetting().setKey(key).setValue(value); + testRunner.accept(newConfiguration); + } + /** * Helper method to verify that the RestResponse matches what was expected. This method assumes a response status of 200. * @@ -552,4 +565,37 @@ static boolean equalsArray(List settings1, List + assertEquals(headerContainer.getValue(httpHeader.getName()), httpHeader.getValue())); + } } diff --git a/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addHeadersFromContextPolicyTest.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addHeadersFromContextPolicyTest.json new file mode 100644 index 000000000000..bffebd98e591 --- /dev/null +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addHeadersFromContextPolicyTest.json @@ -0,0 +1,95 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://appconfigtestshawnfang.azconfig.io/kv/key50977280758?api-version=1.0", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "e9b22ff5-88bb-43dc-9fea-326b62ddcd14", + "Content-Type" : "application/json" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "Server" : "openresty/1.15.8.1", + "Access-Control-Allow-Origin" : "*", + "Access-Control-Allow-Methods" : "GET, PUT, POST, DELETE, PATCH, OPTIONS", + "Connection" : "keep-alive", + "Last-Modified" : "Thu, 12 Dec 2019 01:34:03 GMT", + "retry-after" : "0", + "StatusCode" : "200", + "Date" : "Thu, 12 Dec 2019 01:34:02 GMT", + "Access-Control-Allow-Headers" : "DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Authorization, x-ms-client-request-id, x-ms-command-name, x-ms-content-sha256, x-ms-date, host, Accept, Accept-Datetime, Date, If-Match, If-None-Match, Sync-Token, x-ms-return-client-request-id, ETag, Last-Modified, Link, Memento-Datetime, x-ms-retry-after, x-ms-request-id, WWW-Authenticate", + "x-ms-correlation-request-id" : "d17cf096-d4b2-4e9b-8989-b995883f9220", + "Strict-Transport-Security" : "max-age=15724800; includeSubDomains", + "Access-Control-Expose-Headers" : "DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Authorization, x-ms-client-request-id, x-ms-command-name, x-ms-content-sha256, x-ms-date, host, Accept, Accept-Datetime, Date, If-Match, If-None-Match, Sync-Token, x-ms-return-client-request-id, ETag, Last-Modified, Link, Memento-Datetime, x-ms-retry-after, x-ms-request-id, WWW-Authenticate", + "ETag" : "\"C9lwXgKsyniqCMiZQEMXehlxbJc\"", + "Access-Control-Allow-Credentials" : "true", + "Sync-Token" : "zAJw6V16=MDotMSM2NDQ5OTU=;sn=644995", + "x-ms-request-id" : "d17cf096-d4b2-4e9b-8989-b995883f9220", + "Body" : "{\"etag\":\"C9lwXgKsyniqCMiZQEMXehlxbJc\",\"key\":\"key50977280758\",\"label\":null,\"content_type\":null,\"value\":\"newValue\",\"tags\":{},\"locked\":false,\"last_modified\":\"2019-12-12T01:34:03+00:00\"}", + "x-ms-client-request-id" : "e9b22ff5-88bb-43dc-9fea-326b62ddcd14", + "Content-Type" : "application/vnd.microsoft.appconfig.kv+json; charset=utf-8" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://appconfigtestshawnfang.azconfig.io/kv?key=key50977%2a&api-version=1.0", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "d8137165-1841-4190-a0a4-8dce7975d4c5", + "Content-Type" : "application/json" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "Server" : "openresty/1.15.8.1", + "Access-Control-Allow-Origin" : "*", + "Access-Control-Allow-Methods" : "GET, PUT, POST, DELETE, PATCH, OPTIONS", + "Connection" : "keep-alive", + "retry-after" : "0", + "StatusCode" : "200", + "Date" : "Thu, 12 Dec 2019 01:34:02 GMT", + "Access-Control-Allow-Headers" : "DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Authorization, x-ms-client-request-id, x-ms-command-name, x-ms-content-sha256, x-ms-date, host, Accept, Accept-Datetime, Date, If-Match, If-None-Match, Sync-Token, x-ms-return-client-request-id, ETag, Last-Modified, Link, Memento-Datetime, x-ms-retry-after, x-ms-request-id, WWW-Authenticate", + "x-ms-correlation-request-id" : "54f432e3-19dc-4740-88ea-4eb9568692da", + "Strict-Transport-Security" : "max-age=15724800; includeSubDomains", + "Access-Control-Expose-Headers" : "DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Authorization, x-ms-client-request-id, x-ms-command-name, x-ms-content-sha256, x-ms-date, host, Accept, Accept-Datetime, Date, If-Match, If-None-Match, Sync-Token, x-ms-return-client-request-id, ETag, Last-Modified, Link, Memento-Datetime, x-ms-retry-after, x-ms-request-id, WWW-Authenticate", + "Access-Control-Allow-Credentials" : "true", + "Sync-Token" : "zAJw6V16=MDotMSM2NDQ5OTU=;sn=644995", + "x-ms-request-id" : "54f432e3-19dc-4740-88ea-4eb9568692da", + "Body" : "{\"items\":[{\"etag\":\"C9lwXgKsyniqCMiZQEMXehlxbJc\",\"key\":\"key50977280758\",\"label\":null,\"content_type\":null,\"value\":\"newValue\",\"tags\":{},\"locked\":false,\"last_modified\":\"2019-12-12T01:34:03+00:00\"}]}", + "x-ms-client-request-id" : "d8137165-1841-4190-a0a4-8dce7975d4c5", + "Content-Type" : "application/vnd.microsoft.appconfig.kvset+json; charset=utf-8" + }, + "Exception" : null + }, { + "Method" : "DELETE", + "Uri" : "https://appconfigtestshawnfang.azconfig.io/kv/key50977280758?api-version=1.0", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "6583721c-3230-4d6c-85b7-24fc3dd6d419", + "Content-Type" : "application/json" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "Server" : "openresty/1.15.8.1", + "Access-Control-Allow-Origin" : "*", + "Access-Control-Allow-Methods" : "GET, PUT, POST, DELETE, PATCH, OPTIONS", + "Connection" : "keep-alive", + "Last-Modified" : "Thu, 12 Dec 2019 01:34:03 GMT", + "retry-after" : "0", + "StatusCode" : "200", + "Date" : "Thu, 12 Dec 2019 01:34:02 GMT", + "Access-Control-Allow-Headers" : "DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Authorization, x-ms-client-request-id, x-ms-command-name, x-ms-content-sha256, x-ms-date, host, Accept, Accept-Datetime, Date, If-Match, If-None-Match, Sync-Token, x-ms-return-client-request-id, ETag, Last-Modified, Link, Memento-Datetime, x-ms-retry-after, x-ms-request-id, WWW-Authenticate", + "x-ms-correlation-request-id" : "bd84e592-47bb-42f3-b0dc-2f58afba337e", + "Strict-Transport-Security" : "max-age=15724800; includeSubDomains", + "Access-Control-Expose-Headers" : "DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Authorization, x-ms-client-request-id, x-ms-command-name, x-ms-content-sha256, x-ms-date, host, Accept, Accept-Datetime, Date, If-Match, If-None-Match, Sync-Token, x-ms-return-client-request-id, ETag, Last-Modified, Link, Memento-Datetime, x-ms-retry-after, x-ms-request-id, WWW-Authenticate", + "ETag" : "\"C9lwXgKsyniqCMiZQEMXehlxbJc\"", + "Access-Control-Allow-Credentials" : "true", + "Sync-Token" : "zAJw6V16=MDotMSM2NDQ5OTY=;sn=644996", + "x-ms-request-id" : "bd84e592-47bb-42f3-b0dc-2f58afba337e", + "Body" : "{\"etag\":\"C9lwXgKsyniqCMiZQEMXehlxbJc\",\"key\":\"key50977280758\",\"label\":null,\"content_type\":null,\"value\":\"newValue\",\"tags\":{},\"locked\":false,\"last_modified\":\"2019-12-12T01:34:03+00:00\"}", + "x-ms-client-request-id" : "6583721c-3230-4d6c-85b7-24fc3dd6d419", + "Content-Type" : "application/vnd.microsoft.appconfig.kv+json; charset=utf-8" + }, + "Exception" : null + } ], + "variables" : [ "key50977", "b9ec5bff", "key50977280758" ] +} \ No newline at end of file