Skip to content

Commit c029d7d

Browse files
authored
Add ErrorOptions to RequestOptions (Azure#25130)
Add ErrorOptions to RequestOptions
1 parent e0bc5ed commit c029d7d

File tree

6 files changed

+86
-37
lines changed

6 files changed

+86
-37
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.core.http.rest;
5+
6+
/**
7+
* Determines how errors are handled by requests using {@link RequestOptions}.
8+
*/
9+
public enum ErrorOptions {
10+
/**
11+
* Throw exceptions when an HTTP response with a status code indicating an error (400 or above) is received.
12+
*/
13+
THROW,
14+
15+
/**
16+
* Do not throw exceptions when an HTTP response with a status code indicating an error (400 or above) is received.
17+
*/
18+
NO_THROW
19+
}

sdk/core/azure-core/src/main/java/com/azure/core/http/rest/RequestOptions.java

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,26 @@
88
import com.azure.core.http.HttpRequest;
99
import com.azure.core.util.BinaryData;
1010
import com.azure.core.util.Context;
11+
import com.azure.core.util.logging.ClientLogger;
1112

13+
import java.util.EnumSet;
14+
import java.util.Objects;
1215
import java.util.function.Consumer;
1316

1417
/**
15-
* This class contains the options to customize an HTTP request. {@link RequestOptions} can be
16-
* used to configure the request headers, query params, the request body, or add a callback
17-
* to modify all aspects of the HTTP request.
18+
* This class contains the options to customize an HTTP request. {@link RequestOptions} can be used to configure the
19+
* request headers, query params, the request body, or add a callback to modify all aspects of the HTTP request.
1820
*
1921
* <p>
20-
* An instance of fully configured {@link RequestOptions} can be passed to a service method that
21-
* preconfigures known components of the request like URL, path params etc, further modifying both
22-
* un-configured, or preconfigured components.
22+
* An instance of fully configured {@link RequestOptions} can be passed to a service method that preconfigures known
23+
* components of the request like URL, path params etc, further modifying both un-configured, or preconfigured
24+
* components.
2325
* </p>
2426
*
2527
* <p>
2628
* To demonstrate how this class can be used to construct a request, let's use a Pet Store service as an example. The
27-
* list of APIs available on this service are <a href="https://petstore.swagger.io/#/pet">documented in the swagger definition.</a>
29+
* list of APIs available on this service are <a href="https://petstore.swagger.io/#/pet">documented in the swagger
30+
* definition.</a>
2831
* </p>
2932
*
3033
* <p><strong>Creating an instance of RequestOptions</strong></p>
@@ -37,8 +40,8 @@
3740
* <!-- end com.azure.core.http.rest.requestoptions.instantiation -->
3841
*
3942
* <p><strong>Configuring the request with JSON body and making a HTTP POST request</strong></p>
40-
* To <a href="https://petstore.swagger.io/#/pet/addPet">add a new pet to the pet store</a>, an HTTP POST call should
41-
* be made to the service with the details of the pet that is to be added. The details of the pet are included as the
43+
* To <a href="https://petstore.swagger.io/#/pet/addPet">add a new pet to the pet store</a>, an HTTP POST call should be
44+
* made to the service with the details of the pet that is to be added. The details of the pet are included as the
4245
* request body in JSON format.
4346
*
4447
* The JSON structure for the request is defined as follows:
@@ -112,26 +115,34 @@
112115
* <!-- end com.azure.core.http.rest.requestoptions.postrequest -->
113116
*/
114117
public final class RequestOptions {
115-
private Consumer<HttpRequest> requestCallback = request -> { };
116-
private boolean throwOnError = true;
118+
private static final ClientLogger LOGGER = new ClientLogger(RequestOptions.class);
119+
120+
private static final EnumSet<ErrorOptions> DEFAULT = EnumSet.of(ErrorOptions.THROW);
121+
122+
private Consumer<HttpRequest> requestCallback = request -> {
123+
};
124+
private EnumSet<ErrorOptions> errorOptions = DEFAULT;
117125
private Context context;
118126

119127
/**
120128
* Gets the request callback, applying all the configurations set on this RequestOptions.
129+
*
121130
* @return the request callback
122131
*/
123132
Consumer<HttpRequest> getRequestCallback() {
124133
return this.requestCallback;
125134
}
126135

127136
/**
128-
* Gets whether an exception is thrown when an HTTP response with a status code indicating an error
129-
* (400 or above) is received.
137+
* Gets the {@link ErrorOptions} that determines how error responses (400 or above) are handled.
138+
* <p>
139+
* Default is to throw.
130140
*
131-
* @return true if to throw on status codes of 400 or above, false if not. Default is true.
141+
* @return The {@link ErrorOptions} that determines how error responses (400 or above) are handled. Default is to
142+
* throw.
132143
*/
133-
boolean isThrowOnError() {
134-
return this.throwOnError;
144+
EnumSet<ErrorOptions> getErrorOptions() {
145+
return this.errorOptions;
135146
}
136147

137148
/**
@@ -145,9 +156,9 @@ Context getContext() {
145156

146157
/**
147158
* Adds a header to the HTTP request.
159+
*
148160
* @param header the header key
149161
* @param value the header value
150-
*
151162
* @return the modified RequestOptions object
152163
*/
153164
public RequestOptions addHeader(String header, String value) {
@@ -163,8 +174,8 @@ public RequestOptions addHeader(String header, String value) {
163174
}
164175

165176
/**
166-
* Adds a query parameter to the request URL. The parameter name and value will be URL encoded.
167-
* To use an already encoded parameter name and value, call {@code addQueryParam("name", "value", true)}.
177+
* Adds a query parameter to the request URL. The parameter name and value will be URL encoded. To use an already
178+
* encoded parameter name and value, call {@code addQueryParam("name", "value", true)}.
168179
*
169180
* @param parameterName the name of the query parameter
170181
* @param value the value of the query parameter
@@ -175,9 +186,9 @@ public RequestOptions addQueryParam(String parameterName, String value) {
175186
}
176187

177188
/**
178-
* Adds a query parameter to the request URL, specifying whether the parameter is already encoded.
179-
* A value true for this argument indicates that value of {@link QueryParam#value()} is already encoded
180-
* hence engine should not encode it, by default value will be encoded.
189+
* Adds a query parameter to the request URL, specifying whether the parameter is already encoded. A value true for
190+
* this argument indicates that value of {@link QueryParam#value()} is already encoded hence engine should not
191+
* encode it, by default value will be encoded.
181192
*
182193
* @param parameterName the name of the query parameter
183194
* @param value the value of the query parameter
@@ -195,38 +206,55 @@ public RequestOptions addQueryParam(String parameterName, String value, boolean
195206
}
196207

197208
/**
198-
* Adds a custom request callback to modify the HTTP request before it's sent by the HttpClient.
199-
* The modifications made on a RequestOptions object is applied in order on the request.
209+
* Adds a custom request callback to modify the HTTP request before it's sent by the HttpClient. The modifications
210+
* made on a RequestOptions object is applied in order on the request.
200211
*
201212
* @param requestCallback the request callback
202213
* @return the modified RequestOptions object
214+
* @throws NullPointerException If {@code requestCallback} is null.
203215
*/
204216
public RequestOptions addRequestCallback(Consumer<HttpRequest> requestCallback) {
217+
Objects.requireNonNull(requestCallback, "'requestCallback' cannot be null.");
205218
this.requestCallback = this.requestCallback.andThen(requestCallback);
206219
return this;
207220
}
208221

209222
/**
210223
* Sets the body to send as part of the HTTP request.
224+
*
211225
* @param requestBody the request body data
212226
* @return the modified RequestOptions object
227+
* @throws NullPointerException If {@code requestBody} is null.
213228
*/
214229
public RequestOptions setBody(BinaryData requestBody) {
215-
this.requestCallback = this.requestCallback.andThen(request -> {
216-
request.setBody(requestBody.toBytes());
217-
});
230+
Objects.requireNonNull(requestBody, "'requestBody' cannot be null.");
231+
this.requestCallback = this.requestCallback.andThen(request -> request.setBody(requestBody.toBytes()));
218232
return this;
219233
}
220234

221235
/**
222-
* Sets whether exception is thrown when an HTTP response with a status code indicating an error
223-
* (400 or above) is received. By default, an exception will be thrown when an error response is received.
236+
* Sets the {@link ErrorOptions} that determines how error responses (400 or above) are handled.
237+
* <p>
238+
* Default is to throw.
239+
* <p>
240+
* If both {@link ErrorOptions#THROW} and {@link ErrorOptions#NO_THROW} are included in {@code errorOptions}
241+
* an exception will be thrown as they aren't compatible with each other.
224242
*
225-
* @param throwOnError true if to throw on status codes of 400 or above, false if not. Default is true.
243+
* @param errorOptions The {@link ErrorOptions} that determines how error responses (400 or above) are handled.
226244
* @return the modified RequestOptions object
245+
* @throws NullPointerException If {@code errorOptions} is null.
246+
* @throws IllegalArgumentException If both {@link ErrorOptions#THROW} and {@link ErrorOptions#NO_THROW} are
247+
* included in {@code errorOptions}.
227248
*/
228-
public RequestOptions setThrowOnError(boolean throwOnError) {
229-
this.throwOnError = throwOnError;
249+
public RequestOptions setErrorOptions(EnumSet<ErrorOptions> errorOptions) {
250+
Objects.requireNonNull(errorOptions, "'errorOptions' cannot be null.");
251+
252+
if (errorOptions.contains(ErrorOptions.THROW) && errorOptions.contains(ErrorOptions.NO_THROW)) {
253+
throw LOGGER.logExceptionAsError(new IllegalArgumentException(
254+
"'errorOptions' cannot contain both 'ErrorOptions.THROW' and 'ErrorOptions.NO_THROW'."));
255+
}
256+
257+
this.errorOptions = errorOptions;
230258
return this;
231259
}
232260

sdk/core/azure-core/src/main/java/com/azure/core/http/rest/RestProxy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ private Mono<HttpDecodedResponse> ensureExpectedStatus(final HttpDecodedResponse
420420
// If the response was success or configured to not return an error status when the request fails, return the
421421
// decoded response.
422422
if (methodParser.isExpectedResponseStatusCode(responseStatusCode)
423-
|| (options != null && !options.isThrowOnError())) {
423+
|| (options != null && options.getErrorOptions().contains(ErrorOptions.NO_THROW))) {
424424
return Mono.just(decodedResponse);
425425
}
426426

sdk/core/azure-core/src/test/java/com/azure/core/http/rest/SwaggerMethodParserTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.time.ZoneOffset;
4444
import java.util.Arrays;
4545
import java.util.Collections;
46+
import java.util.EnumSet;
4647
import java.util.HashMap;
4748
import java.util.List;
4849
import java.util.Map;
@@ -522,8 +523,7 @@ private static Stream<Arguments> setRequestOptionsSupplier() throws NoSuchMethod
522523
RequestOptions urlOptions = new RequestOptions()
523524
.addRequestCallback(httpRequest -> httpRequest.setUrl("https://foo.host.com"));
524525

525-
RequestOptions statusOptionOptions = new RequestOptions()
526-
.setThrowOnError(false);
526+
RequestOptions statusOptionOptions = new RequestOptions().setErrorOptions(EnumSet.of(ErrorOptions.NO_THROW));
527527

528528
return Stream.of(
529529
Arguments.of(swaggerMethodParser, null, null),

sdk/webpubsub/azure-messaging-webpubsub/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
<dependency>
4747
<groupId>com.azure</groupId>
4848
<artifactId>azure-core</artifactId>
49-
<version>1.22.0-beta.1</version> <!-- {x-version-update;beta_com.azure:azure-core;dependency} -->
49+
<version>1.22.0-beta.2</version> <!-- {x-version-update;unreleased_com.azure:azure-core;dependency} -->
5050
</dependency>
5151
<dependency>
5252
<groupId>com.azure</groupId>

sdk/webpubsub/azure-messaging-webpubsub/src/test/java/com/azure/messaging/webpubsub/WebPubSubServiceClientTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.azure.core.http.HttpClient;
77
import com.azure.core.http.policy.HttpLogDetailLevel;
88
import com.azure.core.http.policy.HttpLogOptions;
9+
import com.azure.core.http.rest.ErrorOptions;
910
import com.azure.core.http.rest.RequestOptions;
1011
import com.azure.core.http.rest.Response;
1112
import com.azure.core.test.TestBase;
@@ -27,6 +28,7 @@
2728

2829
import java.nio.charset.StandardCharsets;
2930
import java.text.ParseException;
31+
import java.util.EnumSet;
3032

3133
import static org.junit.jupiter.api.Assertions.assertEquals;
3234
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -243,7 +245,7 @@ public void testAadCredential() {
243245
public void testCheckPermission() {
244246
RequestOptions requestOptions = new RequestOptions()
245247
.addQueryParam("targetName", "group_name")
246-
.setThrowOnError(false);
248+
.setErrorOptions(EnumSet.of(ErrorOptions.NO_THROW));
247249
boolean permission = client.checkPermissionWithResponse(WebPubSubPermission.JOIN_LEAVE_GROUP, "connection_id",
248250
requestOptions).getValue();
249251
Assertions.assertFalse(permission);

0 commit comments

Comments
 (0)