Skip to content

Commit

Permalink
feat: expose response header in ApiException.
Browse files Browse the repository at this point in the history
  • Loading branch information
panxl6 committed Dec 16, 2024
1 parent 4f684cd commit de244fb
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 79 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.aftership</groupId>
<artifactId>tracking-sdk</artifactId>
<version>7.0.0</version>
<version>7.1.0</version>

<name>AfterShip Tracking SDK</name>
<description>The official AfterShip Tracking Java API library</description>
Expand Down
48 changes: 23 additions & 25 deletions src/main/java/com/aftership/exception/ApiException.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,70 +4,67 @@
*/
package com.aftership.exception;

import org.apache.http.Header;

import java.util.Arrays;

public class ApiException extends Exception {

private Integer metaCode;
private String message;
private Integer code;
private Integer statusCode;
private String responseBody;
private final Integer metaCode;
private final String message;
private final Integer code;
private final Integer statusCode;
private final String responseBody;
private final Header[] headers;

public ApiException(final int code, final String message) {
this.metaCode = 0;
this.message = message;
this.statusCode = 0;
this.code = code;
this.responseBody = "";
this.headers = null;
}

public ApiException(final int metaCode, final String message, final int code, final int statusCode,
final String responseBody) {
public ApiException(
final int metaCode,
final String message,
final int code,
final int statusCode,
final String responseBody,
final Header[] headers
) {
this.metaCode = metaCode;
this.message = message;
this.code = code;
this.statusCode = statusCode;
this.responseBody = responseBody;
this.headers = headers;
}

public Integer getMetaCode() {
return metaCode;
}

public void setMetaCode(Integer metaCode) {
this.metaCode = metaCode;
}

@Override
public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public Integer getCode() {
return code;
}

public void setCode(Integer code) {
this.code = code;
}

public Integer getStatusCode() {
return statusCode;
}

public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}

public String getResponseBody() {
return responseBody;
}

public void setResponseBody(String responseBody) {
this.responseBody = responseBody;
public Header[] getHeaders() {
return headers;
}

@Override
Expand All @@ -78,6 +75,7 @@ public String toString() {
", code=" + code +
", statusCode=" + statusCode +
", responseBody='" + responseBody + '\'' +
", headers=" + Arrays.toString(headers) +
'}';
}
}
18 changes: 16 additions & 2 deletions src/main/java/com/aftership/http/AfterShipClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,24 @@ public Response request(final Request request) throws Exception {
message = jsonObject.get("meta").getAsJsonObject().get("message").getAsString();
} catch (Exception ignore) {
}
throw new ApiException(metaCode, message, statusCode, ErrorEnum.getByMetaCode(metaCode), response.getContent());
throw new ApiException(
metaCode,
message,
statusCode,
ErrorEnum.getByMetaCode(metaCode),
response.getContent(),
response.getHeaders()
);
}
if (statusCode > 499) {
throw new ApiException(ErrorEnum.UNKNOWN_ERROR.getCode(), ErrorEnum.UNKNOWN_ERROR.getMessage(), ErrorEnum.UNKNOWN_ERROR.getStatusCode(), 0, "");
throw new ApiException(
ErrorEnum.UNKNOWN_ERROR.getCode(),
ErrorEnum.UNKNOWN_ERROR.getMessage(),
ErrorEnum.UNKNOWN_ERROR.getStatusCode(),
0,
"",
response.getHeaders()
);
}
return response;
}
Expand Down
89 changes: 39 additions & 50 deletions src/main/java/com/aftership/http/HttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

import com.aftership.constant.ErrorEnum;
import com.aftership.exception.ApiException;
import org.apache.http.*;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.utils.HttpClientUtils;
Expand All @@ -24,16 +27,10 @@

public class HttpClient {

private static final String RATE_LIMIT_RESET = "x-ratelimit-reset";
private static final String RATE_LIMIT_LIMIT = "x-ratelimit-limit";
private static final String RATE_LIMIT_REMAINING = "x-ratelimit-remaining";

private static final String DEFAULT_USER_AGENT = "aftership-sdk-java/7.0.0 (https://www.aftership.com) apache-httpclient/4.5.14";
private static final String DEFAULT_USER_AGENT = "aftership-sdk-java/7.1.0 (https://www.aftership.com) apache-httpclient/4.5.14";
protected final org.apache.http.client.HttpClient client;
private final String domain;

private RateLimit rateLimit;

public HttpClient(final RequestConfig requestConfig, String userAgent, String domain) {
this.domain = domain;
if (userAgent == null || userAgent.isEmpty()) {
Expand All @@ -53,7 +50,34 @@ public HttpClient(final RequestConfig requestConfig, String userAgent, String do
.build();
}

public Response makeRequest(final Request request) throws Exception {
public Response request(final Request request, int retries) throws Exception {
Response response = null;
int i = 0;
while (i <= retries) {
try {
i++;
response = makeRequest(request);
if (!shouldRetry(response)) {
break;
}
} catch (SocketTimeoutException e) {
if (i > retries) {
throw new ApiException(
0,
ErrorEnum.TIMED_OUT.getMessage(),
ErrorEnum.TIMED_OUT.getCode(),
ErrorEnum.TIMED_OUT.getStatusCode(),
e.getMessage(),
null
);
}
}
Thread.sleep(delay(i));
}
return response;
}

private Response makeRequest(final Request request) throws Exception {
HttpMethod method = request.getMethod();
RequestBuilder builder = RequestBuilder.create(method.toString())
.setUri(this.domain + request.getURL())
Expand All @@ -70,34 +94,19 @@ public Response makeRequest(final Request request) throws Exception {
try {
response = client.execute(builder.build());
HttpEntity entity = response.getEntity();
return new Response(EntityUtils.toString(entity), response.getStatusLine().getStatusCode(), false);
return new Response(
EntityUtils.toString(entity),
response.getStatusLine().getStatusCode(),
false,
response.getAllHeaders()
);
} finally {
if (response != null) {
HttpClientUtils.closeQuietly(response);
}
}
}

public Response request(final Request request, int retries) throws Exception {
Response response = null;
int i = 0;
while (i <= retries) {
try {
i++;
response = makeRequest(request);
if (!shouldRetry(response)) {
break;
}
} catch (SocketTimeoutException e) {
if (i > retries) {
throw new ApiException(0, ErrorEnum.TIMED_OUT.getMessage(), ErrorEnum.TIMED_OUT.getCode(), ErrorEnum.TIMED_OUT.getStatusCode(), e.getMessage());
}
}
Thread.sleep(delay(i));
}
return response;
}

private boolean shouldRetry(Response response) {
if (response.isTimeout()) {
return true;
Expand All @@ -111,24 +120,4 @@ private int delay(int retryAttempt) {
double jitter = delay * (Math.random() - 0.5);
return (int) (Math.max(1, delay + jitter) * 1000);
}

private void setRateLimiting(HttpResponse response) {
if (response == null) {
return;
}
RateLimit rateLimit = new RateLimit();
Header limit = response.getFirstHeader(RATE_LIMIT_LIMIT);
if (limit != null) {
rateLimit.setLimit(Integer.parseInt(limit.getValue()));
}
Header reset = response.getFirstHeader(RATE_LIMIT_RESET);
if (reset != null) {
rateLimit.setReset(Long.parseLong(reset.getValue()));
}
Header remaining = response.getFirstHeader(RATE_LIMIT_REMAINING);
if (remaining != null) {
rateLimit.setRemaining(Integer.parseInt(remaining.getValue()));
}
this.rateLimit = rateLimit;
}
}
11 changes: 10 additions & 1 deletion src/main/java/com/aftership/http/Response.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@
*/
package com.aftership.http;

import org.apache.http.Header;

public class Response {
private final int statusCode;
private final String content;
private final boolean isTimeout;
private final Header[] headers;

public Response() {
this.statusCode = 0;
this.content = "";
this.isTimeout = true;
this.headers = null;
}

public Response(String content, int statusCode, boolean isTimeout) {
public Response(String content, int statusCode, boolean isTimeout, Header[] headers) {
this.content = content;
this.statusCode = statusCode;
this.isTimeout = isTimeout;
this.headers = headers;
}

public String getContent() {
Expand All @@ -32,4 +37,8 @@ public int getStatusCode() {
public boolean isTimeout() {
return isTimeout;
}

public Header[] getHeaders() {
return headers;
}
}

0 comments on commit de244fb

Please sign in to comment.