Skip to content

Commit be58419

Browse files
committed
Add support for HTTP status code in exception.
Signed-off-by: Artur Souza <[email protected]>
1 parent bf39081 commit be58419

File tree

6 files changed

+88
-38
lines changed

6 files changed

+88
-38
lines changed

sdk-actors/src/test/java/io/dapr/actors/client/DaprHttpClientTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public void invokeActorMethodError() {
9191

9292
assertThrowsDaprException(
9393
"ERR_SOMETHING",
94-
"ERR_SOMETHING: error message",
94+
"ERR_SOMETHING: error message (HTTP status code: 404)",
9595
() -> mono.block());
9696
}
9797

sdk-tests/src/test/java/io/dapr/it/pubsub/http/PubSubIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public void publishPubSubNotFound(boolean useGrpc) throws Exception {
122122
} else {
123123
assertThrowsDaprExceptionWithReason(
124124
"ERR_PUBSUB_NOT_FOUND",
125-
"ERR_PUBSUB_NOT_FOUND: pubsub unknown pubsub is not found",
125+
"ERR_PUBSUB_NOT_FOUND: pubsub unknown pubsub is not found (HTTP status code: 404)",
126126
"DAPR_PUBSUB_NOT_FOUND",
127127
() -> client.publishEvent("unknown pubsub", "mytopic", "payload").block());
128128
}

sdk-tests/src/test/java/io/dapr/it/state/HttpStateClientIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public void getStateStoreNotFound() {
6565
// DaprException is guaranteed in the Dapr SDK but getCause() is null in HTTP while present in GRPC implementation.
6666
assertThrowsDaprException(
6767
"ERR_STATE_STORE_NOT_FOUND",
68-
"ERR_STATE_STORE_NOT_FOUND: state store unknown state store is not found",
68+
"ERR_STATE_STORE_NOT_FOUND: state store unknown state store is not found (HTTP status code: 404)",
6969
() -> daprClient.getState("unknown state store", new State(stateKey), byte[].class).block());
7070
}
7171

@@ -78,7 +78,7 @@ public void getStatesStoreNotFound() {
7878
// DaprException is guaranteed in the Dapr SDK but getCause() is null in HTTP while present in GRPC implementation.
7979
assertThrowsDaprException(
8080
"ERR_STATE_STORE_NOT_FOUND",
81-
"ERR_STATE_STORE_NOT_FOUND: state store unknown state store is not found",
81+
"ERR_STATE_STORE_NOT_FOUND: state store unknown state store is not found (HTTP status code: 404)",
8282
() -> daprClient.getBulkState(
8383
"unknown state store",
8484
Collections.singletonList(stateKey),

sdk/src/main/java/io/dapr/client/DaprHttp.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,8 @@ private static DaprError parseDaprError(byte[] json) {
349349
try {
350350
return DAPR_ERROR_DETAILS_OBJECT_MAPPER.readValue(json, DaprError.class);
351351
} catch (IOException e) {
352-
throw new DaprException("UNKNOWN", new String(json, StandardCharsets.UTF_8), json);
352+
// Could not parse DaprError. Return null.
353+
return null;
353354
}
354355
}
355356

@@ -384,17 +385,13 @@ public void onResponse(@NotNull Call call, @NotNull okhttp3.Response response) t
384385
try {
385386
byte[] payload = getBodyBytesOrEmptyArray(response);
386387
DaprError error = parseDaprError(payload);
387-
if ((error != null) && (error.getErrorCode() != null)) {
388-
if (error.getMessage() != null) {
389-
future.completeExceptionally(new DaprException(error, payload));
390-
} else {
391-
future.completeExceptionally(
392-
new DaprException(error.getErrorCode(), "HTTP status code: " + response.code(), payload));
393-
}
388+
if (error != null) {
389+
future.completeExceptionally(new DaprException(error, payload, response.code()));
394390
return;
395391
}
396392

397-
future.completeExceptionally(new DaprException("UNKNOWN", "HTTP status code: " + response.code(), payload));
393+
future.completeExceptionally(
394+
new DaprException("UNKNOWN", "", payload, response.code()));
398395
return;
399396
} catch (DaprException e) {
400397
future.completeExceptionally(e);

sdk/src/main/java/io/dapr/exceptions/DaprException.java

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313

1414
package io.dapr.exceptions;
1515

16+
import com.google.rpc.Status;
1617
import io.grpc.StatusRuntimeException;
18+
import io.grpc.protobuf.StatusProto;
1719
import reactor.core.Exceptions;
1820
import reactor.core.publisher.Flux;
1921
import reactor.core.publisher.Mono;
@@ -30,26 +32,32 @@ public class DaprException extends RuntimeException {
3032
/**
3133
* Dapr's error code for this exception.
3234
*/
33-
private String errorCode;
35+
private final String errorCode;
3436

3537
/**
3638
* The status details for the error.
3739
*/
38-
private DaprErrorDetails errorDetails;
40+
private final DaprErrorDetails errorDetails;
3941

4042
/**
4143
* Optional payload, if the exception came from a response body.
4244
*/
43-
private byte[] payload;
45+
private final byte[] payload;
46+
47+
/**
48+
* Optional HTTP status code, if error happened for an HTTP call (0 if not set).
49+
*/
50+
private final int httpStatusCode;
4451

4552
/**
4653
* New exception from a server-side generated error code and message.
4754
*
4855
* @param daprError Server-side error.
49-
* @param payload Payload containing the error.
56+
* @param payload Optional payload containing the error.
57+
* @param httpStatusCode Optional http Status Code (0 if not set).
5058
*/
51-
public DaprException(DaprError daprError, byte[] payload) {
52-
this(daprError.getErrorCode(), daprError.getMessage(), daprError.getDetails(), payload);
59+
public DaprException(DaprError daprError, byte[] payload, int httpStatusCode) {
60+
this(daprError.getErrorCode(), daprError.getMessage(), daprError.getDetails(), payload, httpStatusCode);
5361
}
5462

5563
/**
@@ -77,10 +85,11 @@ public DaprException(Throwable exception) {
7785
*
7886
* @param errorCode Client-side error code.
7987
* @param message Client-side error message.
80-
* @param payload Error's raw payload.
88+
* @param payload Optional payload containing the error.
89+
* @param httpStatusCode Optional http Status Code (0 if not set).
8190
*/
82-
public DaprException(String errorCode, String message, byte[] payload) {
83-
this(errorCode, message, DaprErrorDetails.EMPTY_INSTANCE, payload);
91+
public DaprException(String errorCode, String message, byte[] payload, int httpStatusCode) {
92+
this(errorCode, message, DaprErrorDetails.EMPTY_INSTANCE, payload, httpStatusCode);
8493
}
8594

8695
/**
@@ -89,10 +98,12 @@ public DaprException(String errorCode, String message, byte[] payload) {
8998
* @param errorCode Client-side error code.
9099
* @param message Client-side error message.
91100
* @param errorDetails Details of the error from runtime.
92-
* @param payload Payload containing the error.
101+
* @param payload Optional payload containing the error.
102+
* @param httpStatusCode Optional http Status Code (0 if not set).
93103
*/
94-
public DaprException(String errorCode, String message, List<Map<String, Object>> errorDetails, byte[] payload) {
95-
this(errorCode, message, new DaprErrorDetails(errorDetails), payload);
104+
public DaprException(
105+
String errorCode, String message, List<Map<String, Object>> errorDetails, byte[] payload, int httpStatusCode) {
106+
this(errorCode, message, new DaprErrorDetails(errorDetails), payload, httpStatusCode);
96107
}
97108

98109
/**
@@ -101,10 +112,29 @@ public DaprException(String errorCode, String message, List<Map<String, Object>>
101112
* @param errorCode Client-side error code.
102113
* @param message Client-side error message.
103114
* @param errorDetails Details of the error from runtime.
104-
* @param payload Payload containing the error.
115+
* @param payload Optional payload containing the error.
105116
*/
106117
public DaprException(String errorCode, String message, DaprErrorDetails errorDetails, byte[] payload) {
107-
super(String.format("%s: %s", errorCode, message));
118+
this(errorCode, message, errorDetails, payload, 0);
119+
}
120+
121+
/**
122+
* New Exception from a client-side generated error code and message.
123+
*
124+
* @param errorCode Client-side error code.
125+
* @param message Client-side error message.
126+
* @param errorDetails Details of the error from runtime.
127+
* @param payload Optional payload containing the error.
128+
* @param httpStatusCode Optional http Status Code (0 if not set).
129+
*/
130+
public DaprException(
131+
String errorCode,
132+
String message,
133+
DaprErrorDetails errorDetails,
134+
byte[] payload,
135+
int httpStatusCode) {
136+
super(buildErrorMessage(errorCode, httpStatusCode, message));
137+
this.httpStatusCode = httpStatusCode;
108138
this.errorCode = errorCode;
109139
this.errorDetails = errorDetails;
110140
this.payload = payload;
@@ -120,8 +150,11 @@ public DaprException(String errorCode, String message, DaprErrorDetails errorDet
120150
* unknown.)
121151
*/
122152
public DaprException(String errorCode, String message, Throwable cause) {
123-
super(String.format("%s: %s", errorCode, emptyIfNull(message)), cause);
153+
super(buildErrorMessage(errorCode, 0, message), cause);
154+
this.httpStatusCode = 0;
124155
this.errorCode = errorCode;
156+
this.errorDetails = DaprErrorDetails.EMPTY_INSTANCE;
157+
this.payload = null;
125158
}
126159

127160
/**
@@ -137,7 +170,8 @@ public DaprException(String errorCode, String message, Throwable cause) {
137170
*/
138171
public DaprException(
139172
String errorCode, String message, Throwable cause, DaprErrorDetails errorDetails, byte[] payload) {
140-
super(String.format("%s: %s", errorCode, emptyIfNull(message)), cause);
173+
super(buildErrorMessage(errorCode, 0, message), cause);
174+
this.httpStatusCode = 0;
141175
this.errorCode = errorCode;
142176
this.errorDetails = errorDetails == null ? DaprErrorDetails.EMPTY_INSTANCE : errorDetails;
143177
this.payload = payload;
@@ -170,6 +204,15 @@ public byte[] getPayload() {
170204
return this.payload == null ? null : this.payload.clone();
171205
}
172206

207+
/**
208+
* Returns the exception's http status code, 0 if not applicable.
209+
*
210+
* @return Http status code (0 if not applicable).
211+
*/
212+
public int getHttpStatusCode() {
213+
return this.httpStatusCode;
214+
}
215+
173216
/**
174217
* Wraps an exception into DaprException (if not already DaprException).
175218
*
@@ -266,7 +309,7 @@ public static RuntimeException propagate(Throwable exception) {
266309
while (e != null) {
267310
if (e instanceof StatusRuntimeException) {
268311
StatusRuntimeException statusRuntimeException = (StatusRuntimeException) e;
269-
com.google.rpc.Status status = io.grpc.protobuf.StatusProto.fromThrowable(statusRuntimeException);
312+
Status status = StatusProto.fromThrowable(statusRuntimeException);
270313

271314
DaprErrorDetails errorDetails = new DaprErrorDetails(status);
272315

@@ -289,11 +332,18 @@ public static RuntimeException propagate(Throwable exception) {
289332
return new DaprException(exception);
290333
}
291334

292-
private static String emptyIfNull(String str) {
293-
if (str == null) {
294-
return "";
335+
private static String buildErrorMessage(String errorCode, int httpStatusCode, String message) {
336+
String result = ((errorCode == null) || errorCode.isEmpty()) ? "UNKNOWN: " : errorCode + ": ";
337+
if ((message == null) || message.isEmpty()) {
338+
if (httpStatusCode > 0) {
339+
return result + "HTTP status code: " + httpStatusCode;
340+
}
341+
return result;
295342
}
296343

297-
return str;
344+
if (httpStatusCode > 0) {
345+
return result + message + " (HTTP status code: " + httpStatusCode + ")";
346+
}
347+
return result + message;
298348
}
299349
}

sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,8 @@ public void invokeServiceDaprError() {
374374
});
375375

376376
assertEquals("MYCODE", exception.getErrorCode());
377-
assertEquals("MYCODE: My Message", exception.getMessage());
377+
assertEquals("MYCODE: My Message (HTTP status code: 500)", exception.getMessage());
378+
assertEquals(500, exception.getHttpStatusCode());
378379
}
379380

380381
@Test
@@ -408,7 +409,7 @@ public void invokeServiceDaprErrorUnknownJSON() {
408409
});
409410

410411
assertEquals("UNKNOWN", exception.getErrorCode());
411-
assertEquals("UNKNOWN: { \"anything\": 7 }", exception.getMessage());
412+
assertEquals("UNKNOWN: HTTP status code: 500", exception.getMessage());
412413
assertEquals("{ \"anything\": 7 }", new String(exception.getPayload()));
413414
}
414415

@@ -1340,8 +1341,10 @@ public void getSecrets404WithErrorCode() {
13401341
"{\"errorCode\":\"ERR_SECRET_STORE_NOT_FOUND\"," +
13411342
"\"message\":\"error message\"}", MediaTypes.MEDIATYPE_JSON));
13421343

1343-
assertThrowsDaprException("ERR_SECRET_STORE_NOT_FOUND", "ERR_SECRET_STORE_NOT_FOUND: error message", () ->
1344-
daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block()
1344+
assertThrowsDaprException(
1345+
"ERR_SECRET_STORE_NOT_FOUND",
1346+
"ERR_SECRET_STORE_NOT_FOUND: error message (HTTP status code: 404)",
1347+
() -> daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block()
13451348
);
13461349
}
13471350

0 commit comments

Comments
 (0)