Skip to content

Commit

Permalink
Merge pull request #277 from avaje/feature/HttpException-response-body
Browse files Browse the repository at this point in the history
[http client] HttpException add isPlainText() and contentType()
  • Loading branch information
SentryMan authored Aug 24, 2023
2 parents 63f88be + a99350b commit a142f93
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

final class DHttpClientContext implements HttpClient, SpiHttpClient {

Expand Down Expand Up @@ -200,7 +202,7 @@ public long avgMicros() {
}

@SuppressWarnings("unchecked")
public BodyContent readErrorContent(boolean responseAsBytes, HttpResponse<?> httpResponse) {
BodyContent readErrorContent(boolean responseAsBytes, HttpResponse<?> httpResponse) {
if (responseAsBytes) {
return readContent((HttpResponse<byte[]>) httpResponse);
}
Expand All @@ -209,6 +211,13 @@ public BodyContent readErrorContent(boolean responseAsBytes, HttpResponse<?> htt
if (body instanceof String) {
return new BodyContent(contentType, ((String) body).getBytes(StandardCharsets.UTF_8));
}
if (body instanceof Stream) {
var sb = new StringBuilder(50);
for (Object line : ((Stream<Object>) body).collect(Collectors.toList())) {
sb.append(line);
}
return new BodyContent(contentType, sb.toString().getBytes(StandardCharsets.UTF_8));
}
final String type = (body == null) ? "null" : body.getClass().toString();
throw new IllegalStateException("Unable to translate response body to bytes? Maybe use HttpResponse directly instead? Response body type: " + type);
}
Expand Down
15 changes: 15 additions & 0 deletions http-client/src/main/java/io/avaje/http/client/HttpException.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

/**
* HTTP Exception with support for converting the error response body into a bean.
Expand Down Expand Up @@ -151,4 +152,18 @@ public HttpResponse<?> httpResponse() {
return httpResponse;
}

/**
* Return the response Content-Type header.
*/
public Optional<String> contentType() {
return httpResponse.headers().firstValue("Content-Type");
}

/**
* Return true if the Content-Type is text/plain.
*/
public boolean isPlainText() {
return "text/plain".equals(contentType().orElse(null));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,12 @@ void get_stream_NotFoundException() {
assertThat(metrics.errorCount()).isEqualTo(1);
assertThat(metrics.responseBytes()).isEqualTo(0);
assertThat(metrics.totalMicros()).isGreaterThan(0);

assertThat(httpException.bodyAsString()).isEqualTo("Not Found");
assertThat(httpException.isPlainText()).isTrue();
assertThat(httpException.contentType())
.isPresent()
.get().isEqualTo("text/plain");
}

@Test
Expand Down Expand Up @@ -798,6 +804,20 @@ void async_list_as() throws ExecutionException, InterruptedException {
assertThat(helloRes).isSameAs(ref.get());
}

@Test
void get_bean_404() {
try {
clientContext.request()
.path("does-not-exist")
.GET()
.bean(HelloDto.class);
} catch (HttpException e) {
assertThat(e.statusCode()).isEqualTo(404);
assertThat(e.contentType()).isPresent().get().isEqualTo("text/plain");
assertThat(e.bodyAsString()).isEqualTo("Not Found");
}
}

@Test
void get_withPathParamAndQueryParam_returningBean() {

Expand Down Expand Up @@ -1243,6 +1263,12 @@ void postForm_asBytes_validation_expect_badRequest_extractError() {
assertNotNull(httpResponse);
assertEquals(422, httpResponse.statusCode());

assertThat(e.contentType())
.isPresent()
.get().isEqualTo("application/json");

assertThat(e.isPlainText()).isFalse();

final ErrorResponse errorResponse = e.bean(ErrorResponse.class);
assertThat(errorResponse.get("url")).isEqualTo("must be a valid URL");
assertThat(errorResponse.get("name")).isEqualTo("must not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,35 @@

public class MappedException extends RuntimeException {

public MappedException(HttpException e) {}
private final int statusCode;
private String responseMessage;
private MyJsonErrorPayload myPayload;

public MappedException(HttpException httpException) {
super("Error response with statusCode: " + httpException.statusCode());
this.statusCode = httpException.statusCode();
if (httpException.isPlainText()) {
this.responseMessage = httpException.bodyAsString();
} else {
this.myPayload = httpException.bean(MyJsonErrorPayload.class);
}
addSuppressed(httpException);
}

public int statusCode() {
return statusCode;
}

public String responseMessage() {
return responseMessage;
}

public MyJsonErrorPayload myPayload() {
return myPayload;
}

// @Json
static class MyJsonErrorPayload {
// fields
}
}

0 comments on commit a142f93

Please sign in to comment.