-
Notifications
You must be signed in to change notification settings - Fork 2.2k
App Config - Head Requests #48899
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
App Config - Head Requests #48899
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -84,7 +84,8 @@ | |
| * <!-- src_embed com.azure.data.applicationconfig.async.configurationclient.instantiation --> | ||
| * <pre> | ||
| * ConfigurationAsyncClient configurationAsyncClient = new ConfigurationClientBuilder() | ||
| * .connectionString(connectionString) | ||
| * .credential(new DefaultAzureCredentialBuilder().build()) | ||
| * .endpoint(endpoint) | ||
| * .buildAsyncClient(); | ||
| * </pre> | ||
| * <!-- end com.azure.data.applicationconfig.async.configurationclient.instantiation --> | ||
|
|
@@ -1050,6 +1051,56 @@ public PagedFlux<ConfigurationSetting> listConfigurationSettings(SettingSelector | |
| .map(ConfigurationSettingDeserializationHelper::toConfigurationSettingWithPagedResponse))); | ||
| } | ||
|
|
||
| /** | ||
| * Checks configuration settings using a HEAD request, returning only headers without the response body. | ||
| * This is useful for efficiently checking if settings have changed by comparing ETags. | ||
| * | ||
| * <p>The returned items will be empty since HEAD requests do not return a body. Use {@code byPage()} iteration | ||
| * to access page-level ETags for change detection.</p> | ||
| * | ||
| * <p><strong>Code Samples</strong></p> | ||
| * | ||
| * <p>Check all settings that use the key "prodDBConnection".</p> | ||
| * | ||
| * <!-- src_embed com.azure.data.appconfiguration.configurationasyncclient.checkConfigurationSettings --> | ||
| * <pre> | ||
| * SettingSelector selector = new SettingSelector().setKeyFilter("my-app/*"); | ||
| * client.checkConfigurationSettings(selector) | ||
| * .byPage() | ||
| * .subscribe(page -> { | ||
| * System.out.println("Status code: " + page.getStatusCode()); | ||
| * System.out.println("Page ETag: " + page.getHeaders().getValue(com.azure.core.http.HttpHeaderName.ETAG)); | ||
| * }); | ||
| * </pre> | ||
| * <!-- end com.azure.data.appconfiguration.configurationasyncclient.checkConfigurationSettings --> | ||
|
Comment on lines
+1065
to
+1075
|
||
| * | ||
| * @param selector Optional. Selector to filter configuration setting results from the service. | ||
| * @return A Flux of ConfigurationSettings with empty items. Use {@code byPage()} to access page-level ETags. | ||
| * @throws HttpResponseException If a client or service error occurs, such as a 404, 409, 429 or 500. | ||
| */ | ||
| @ServiceMethod(returns = ReturnType.COLLECTION) | ||
| public PagedFlux<ConfigurationSetting> checkConfigurationSettings(SettingSelector selector) { | ||
| final String keyFilter = selector == null ? null : selector.getKeyFilter(); | ||
| final String labelFilter = selector == null ? null : selector.getLabelFilter(); | ||
| final String acceptDateTime = selector == null ? null : selector.getAcceptDateTime(); | ||
| final List<SettingFields> settingFields = selector == null ? null : toSettingFieldsList(selector.getFields()); | ||
| final List<MatchConditions> matchConditionsList = selector == null ? null : selector.getMatchConditions(); | ||
| final List<String> tagsFilter = selector == null ? null : selector.getTagsFilter(); | ||
| AtomicInteger pageETagIndex = new AtomicInteger(0); | ||
| return new PagedFlux<>(() -> withContext(context -> serviceClient | ||
| .checkKeyValuesWithResponseAsync(keyFilter, labelFilter, null, acceptDateTime, settingFields, null, null, | ||
| getPageETag(matchConditionsList, pageETagIndex), tagsFilter, context) | ||
| .map(Utility::toHeadPagedResponse) | ||
| .onErrorResume(HttpResponseException.class, | ||
| (Function<HttpResponseException, Mono<PagedResponse<ConfigurationSetting>>>) Utility::handleHeadNotModifiedErrorToValidResponse)), | ||
| afterToken -> withContext(context -> serviceClient | ||
| .checkKeyValuesWithResponseAsync(keyFilter, labelFilter, afterToken, acceptDateTime, settingFields, | ||
| null, null, getPageETag(matchConditionsList, pageETagIndex), tagsFilter, context) | ||
| .map(Utility::toHeadPagedResponse) | ||
| .onErrorResume(HttpResponseException.class, | ||
| (Function<HttpResponseException, Mono<PagedResponse<ConfigurationSetting>>>) Utility::handleHeadNotModifiedErrorToValidResponse))); | ||
| } | ||
|
|
||
| /** | ||
| * Fetches the configuration settings in a snapshot that matches the {@code snapshotName}. If {@code snapshotName} | ||
| * is {@code null}, then all the {@link ConfigurationSetting configuration settings} are fetched with their | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,6 +11,7 @@ | |||||||
| import com.azure.core.exception.ResourceModifiedException; | ||||||||
| import com.azure.core.exception.ResourceNotFoundException; | ||||||||
| import com.azure.core.http.HttpResponse; | ||||||||
| import com.azure.core.http.HttpHeaderName; | ||||||||
|
||||||||
| import com.azure.core.http.HttpHeaderName; |
Copilot
AI
Apr 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The <!-- src_embed ... --> instantiation snippet content no longer matches the source snippet in ConfigurationClientJavaDocCodeSnippets.java (which still uses .connectionString(connectionString)). The codesnippet Maven plugin will fail validation/injection during build; update the snippet source (BEGIN/END block) instead, or revert this embedded code to match it.
| * .credential(new DefaultAzureCredentialBuilder().build()) | |
| * .endpoint(endpoint) | |
| * .connectionString(connectionString) |
Copilot
AI
Apr 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This JavaDoc references a new codesnippet ID (com.azure.data.applicationconfig.configurationclient.checkConfigurationSettings#settingSelector), but there is no corresponding // BEGIN: / // END: snippet in the module sources. This will cause the codesnippet Maven plugin to fail; add the snippet to the appropriate *JavaDocCodeSnippets.java file or remove the src_embed/end markers if injection isn’t intended.
Copilot
AI
Apr 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate <!-- src_embed ... --> marker line will confuse the codesnippet injection/validation step. Remove the extra src_embed line so there is exactly one start marker paired with the <!-- end ... -->.
| * <!-- src_embed com.azure.data.applicationconfig.configurationclient.checkConfigurationSettings#settingSelector-context --> |
Copilot
AI
Apr 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This src_embed ID for the context overload (...checkConfigurationSettings#settingSelector-context) doesn’t appear to exist as a // BEGIN: / // END: snippet in the module sources. Add the missing snippet to the *JavaDocCodeSnippets.java sources so codesnippet validation passes.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,7 +72,8 @@ | |
| * <!-- src_embed com.azure.data.applicationconfig.async.configurationclient.instantiation --> | ||
| * <pre> | ||
| * ConfigurationAsyncClient configurationAsyncClient = new ConfigurationClientBuilder() | ||
| * .connectionString(connectionString) | ||
| * .credential(new DefaultAzureCredentialBuilder().build()) | ||
| * .endpoint(endpoint) | ||
| * .buildAsyncClient(); | ||
| * </pre> | ||
| * <!-- end com.azure.data.applicationconfig.async.configurationclient.instantiation --> | ||
|
|
@@ -82,7 +83,8 @@ | |
| * <!-- src_embed com.azure.data.applicationconfig.configurationclient.instantiation --> | ||
| * <pre> | ||
| * ConfigurationClient configurationClient = new ConfigurationClientBuilder() | ||
| * .connectionString(connectionString) | ||
| * .credential(new DefaultAzureCredentialBuilder().build()) | ||
| * .endpoint(endpoint) | ||
| * .buildClient(); | ||
| * </pre> | ||
| * <!-- end com.azure.data.applicationconfig.configurationclient.instantiation --> | ||
|
Comment on lines
72
to
90
|
||
|
|
@@ -102,7 +104,7 @@ | |
| * ConfigurationClient configurationClient = new ConfigurationClientBuilder() | ||
| * .pipeline(pipeline) | ||
| * .endpoint("https://dummy.azure.net/") | ||
| * .connectionString(connectionString) | ||
| * .credential(new DefaultAzureCredentialBuilder().build()) | ||
| * .buildClient(); | ||
| * </pre> | ||
| * <!-- end com.azure.data.applicationconfig.configurationclient.pipeline.instantiation --> | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |||||
| import com.azure.core.util.Context; | ||||||
| import com.azure.core.util.CoreUtils; | ||||||
| import com.azure.core.util.logging.ClientLogger; | ||||||
| import com.azure.data.appconfiguration.implementation.models.CheckKeyValuesHeaders; | ||||||
| import com.azure.data.appconfiguration.implementation.models.KeyValue; | ||||||
| import com.azure.data.appconfiguration.implementation.models.SnapshotUpdateParameters; | ||||||
| import com.azure.data.appconfiguration.implementation.models.UpdateSnapshotHeaders; | ||||||
|
|
@@ -26,6 +27,7 @@ | |||||
|
|
||||||
| import java.util.ArrayList; | ||||||
| import java.util.Arrays; | ||||||
| import java.util.Collections; | ||||||
| import java.util.List; | ||||||
| import java.util.Map; | ||||||
| import java.util.Objects; | ||||||
|
|
@@ -210,4 +212,62 @@ public static List<String> getTagsFilterInString(Map<String, String> tagsFilter) | |||||
| } | ||||||
| return tagsFilters; | ||||||
| } | ||||||
|
|
||||||
| // Parse the 'after' query parameter value from the Link header. | ||||||
| // Link header format: </kv?api-version=2023-10-01&$Select=&after=a2V5MTg4Cg%3D%3D>; rel="next" | ||||||
| public static String parseAfterParam(String linkHeader) { | ||||||
| String nextLink = parseNextLink(linkHeader); | ||||||
| if (nextLink == null) { | ||||||
| return null; | ||||||
| } | ||||||
| int afterIdx = nextLink.indexOf("after="); | ||||||
| if (afterIdx == -1) { | ||||||
| return null; | ||||||
| } | ||||||
| String afterValue = nextLink.substring(afterIdx + 6); | ||||||
| int ampIdx = afterValue.indexOf('&'); | ||||||
| return ampIdx != -1 ? afterValue.substring(0, ampIdx) : afterValue; | ||||||
|
Comment on lines
+216
to
+229
|
||||||
| } | ||||||
|
|
||||||
| // Convert a HEAD response to a PagedResponse with empty items. | ||||||
| public static PagedResponse<ConfigurationSetting> | ||||||
| toHeadPagedResponse(ResponseBase<CheckKeyValuesHeaders, Void> response) { | ||||||
| String continuationToken = parseAfterParam(response.getHeaders().getValue(HttpHeaderName.LINK)); | ||||||
| return new PagedResponseBase<>(response.getRequest(), response.getStatusCode(), response.getHeaders(), | ||||||
| Collections.emptyList(), continuationToken, null); | ||||||
| } | ||||||
|
|
||||||
| // Handle 304 status code from HEAD request to a valid response - Async handler | ||||||
| public static Mono<PagedResponse<ConfigurationSetting>> | ||||||
| handleHeadNotModifiedErrorToValidResponse(HttpResponseException error) { | ||||||
| HttpResponse httpResponse = error.getResponse(); | ||||||
| if (httpResponse == null) { | ||||||
| return Mono.error(error); | ||||||
| } | ||||||
|
|
||||||
| String continuationToken = parseAfterParam(httpResponse.getHeaderValue(HttpHeaderName.LINK)); | ||||||
| if (httpResponse.getStatusCode() == 304) { | ||||||
| return Mono.just(new PagedResponseBase<>(httpResponse.getRequest(), httpResponse.getStatusCode(), | ||||||
| httpResponse.getHeaders(), Collections.emptyList(), continuationToken, null)); | ||||||
| } | ||||||
|
|
||||||
| return Mono.error(error); | ||||||
| } | ||||||
|
|
||||||
| // Handle 304 status code from HEAD request to a valid response - Sync handler | ||||||
| public static PagedResponse<ConfigurationSetting> | ||||||
| handleHeadNotModifiedErrorToValidResponse(HttpResponseException error, ClientLogger logger, boolean isHead) { | ||||||
|
||||||
| handleHeadNotModifiedErrorToValidResponse(HttpResponseException error, ClientLogger logger, boolean isHead) { | |
| handleHeadNotModifiedErrorToValidResponse(HttpResponseException error, ClientLogger logger) { |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,7 +34,8 @@ | |
| * <!-- src_embed com.azure.data.applicationconfig.async.configurationclient.instantiation --> | ||
| * <pre> | ||
| * ConfigurationAsyncClient configurationAsyncClient = new ConfigurationClientBuilder() | ||
| * .connectionString(connectionString) | ||
| * .credential(new DefaultAzureCredentialBuilder().build()) | ||
| * .endpoint(endpoint) | ||
| * .buildAsyncClient(); | ||
| * </pre> | ||
|
Comment on lines
34
to
40
|
||
| * <!-- end com.azure.data.applicationconfig.async.configurationclient.instantiation --> | ||
|
|
@@ -48,7 +49,8 @@ | |
| * <!-- src_embed com.azure.data.applicationconfig.configurationclient.instantiation --> | ||
| * <pre> | ||
| * ConfigurationClient configurationClient = new ConfigurationClientBuilder() | ||
| * .connectionString(connectionString) | ||
| * .credential(new DefaultAzureCredentialBuilder().build()) | ||
| * .endpoint(endpoint) | ||
| * .buildClient(); | ||
| * </pre> | ||
|
Comment on lines
34
to
55
|
||
| * <!-- end com.azure.data.applicationconfig.configurationclient.instantiation --> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The instantiation
src_embedblock content here was changed to usecredential()+endpoint(), but the snippet source (ConfigurationClientJavaDocCodeSnippets.java,BEGIN: com.azure.data.applicationconfig.async.configurationclient.instantiation) still uses.connectionString(connectionString). Update the snippet source and let the codesnippet plugin inject, otherwise builds will fail snippet validation.