Skip to content
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

[http client] HttpException add isPlainText() and contentType() #277

Merged
merged 2 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
}