Skip to content

Commit 99c4d98

Browse files
authored
chore: Region set and encode query params (#755)
* chore: fix error response and rest client * Set region and Encode Query params
1 parent 519d5a9 commit 99c4d98

9 files changed

Lines changed: 242 additions & 33 deletions

File tree

src/main/java/com/sendgrid/ApiKeySendGrid.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.sendgrid;
22

3+
import com.sendgrid.constant.EnumConstants;
34
import com.sendgrid.constant.ErrorMessages;
45
import com.sendgrid.exception.AuthenticationException;
56
import com.sendgrid.http.ApiKeyRestClient;
@@ -39,6 +40,9 @@ public static synchronized void setRegion(final String region) {
3940
if (region == null || region.isEmpty()) {
4041
throw new AuthenticationException(String.format(ErrorMessages.EMPTY_STRING, "REGION"));
4142
}
43+
if (!EnumConstants.Region.getValues().contains(region)) {
44+
throw new AuthenticationException(String.format(ErrorMessages.INVALID_STRING, "REGION"));
45+
}
4246
if (!Objects.equals(region, ApiKeySendGrid.region)) {
4347
ApiKeySendGrid.invalidate();
4448
}
@@ -77,8 +81,10 @@ private static ApiKeyRestClient buildRestClient() {
7781
if (userAgentExtensions != null) {
7882
builder.userAgentExtensions(ApiKeySendGrid.userAgentExtensions);
7983
}
80-
// TODO: Check if it mandatory to fetch region from customer.
81-
builder.region(region);
84+
if (region == null)
85+
builder.region(EnumConstants.Region.GLOBAL.getValue());
86+
else
87+
builder.region(region);
8288
return builder.build();
8389
}
8490

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.sendgrid.constant;
2+
3+
public enum Domains {
4+
API("api");
5+
private final String value;
6+
7+
private Domains(final String value) {
8+
this.value = value;
9+
}
10+
11+
public String toString() {
12+
return value;
13+
}
14+
}

src/main/java/com/sendgrid/constant/EnumConstants.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
import lombok.Getter;
44
import lombok.RequiredArgsConstructor;
55

6+
import java.util.Arrays;
7+
import java.util.List;
8+
import java.util.stream.Collectors;
9+
610
public class EnumConstants {
711
@Getter
812
@RequiredArgsConstructor
@@ -12,4 +16,19 @@ public enum ContentType {
1216

1317
private final String value;
1418
}
19+
20+
@Getter
21+
@RequiredArgsConstructor
22+
public enum Region {
23+
GLOBAL("global"),
24+
EU("eu");
25+
26+
private final String value;
27+
28+
public static List<String> getValues() {
29+
return Arrays.stream(Region.values())
30+
.map(Region::getValue)
31+
.collect(Collectors.toList());
32+
}
33+
}
1534
}

src/main/java/com/sendgrid/constant/ErrorMessages.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@
66
@UtilityClass
77
public class ErrorMessages {
88
public static final String EMPTY_STRING = "'%s' can not be null or empty";
9+
10+
public static final String INVALID_STRING = "'%s' is invalid";
911
public static final String DEFAULT_REST_CLIENT = "Sending API request using default '%s' RestClient";
1012
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.sendgrid.exception;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import lombok.Getter;
6+
import lombok.Setter;
7+
import lombok.ToString;
8+
9+
import java.util.List;
10+
import java.util.StringJoiner;
11+
12+
@ToString
13+
public class GenericApiError {
14+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
15+
@JsonProperty("errors")
16+
@Getter
17+
@Setter
18+
private List<GenericError> errors;
19+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
20+
@JsonProperty("id")
21+
@Getter
22+
@Setter
23+
private String id;
24+
25+
public GenericApiError() {
26+
}
27+
28+
private GenericApiError(GenericApiError.Builder builder) {
29+
this.errors = builder.errors;
30+
this.id = builder.id;
31+
}
32+
33+
// Builder class for constructing object
34+
public static class Builder {
35+
private List<GenericError> errors;
36+
private String id;
37+
38+
public Builder() {
39+
}
40+
41+
public GenericApiError.Builder errors(List<GenericError> errors) {
42+
this.errors = errors;
43+
return this;
44+
}
45+
46+
public GenericApiError.Builder id(String id) {
47+
this.id = id;
48+
return this;
49+
}
50+
51+
public GenericApiError build() {
52+
return new GenericApiError(this);
53+
}
54+
55+
}
56+
57+
@Override
58+
public String toString() {
59+
StringJoiner joiner = new StringJoiner(", ", GenericApiError.class.getSimpleName() + "(", ")");
60+
if (errors != null) joiner.add("errors=" + errors);
61+
if (id != null) joiner.add("id=" + id);
62+
return joiner.toString();
63+
}
64+
65+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.sendgrid.exception;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import lombok.Getter;
6+
import lombok.Setter;
7+
import lombok.ToString;
8+
9+
import java.util.StringJoiner;
10+
11+
@ToString
12+
public class GenericError {
13+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
14+
@JsonProperty("message")
15+
@Getter
16+
@Setter
17+
private String message;
18+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
19+
@JsonProperty("field")
20+
@Getter
21+
@Setter
22+
private String field;
23+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
24+
@JsonProperty("help")
25+
@Getter
26+
@Setter
27+
private Object help;
28+
29+
public GenericError() {
30+
}
31+
32+
private GenericError(GenericError.Builder builder) {
33+
this.message = builder.message;
34+
this.field = builder.field;
35+
this.help = builder.help;
36+
}
37+
38+
// Builder class for constructing object
39+
public static class Builder {
40+
private String message;
41+
private String field;
42+
private Object help;
43+
44+
public Builder() {
45+
}
46+
47+
public GenericError.Builder message(String message) {
48+
this.message = message;
49+
return this;
50+
}
51+
52+
public GenericError.Builder field(String field) {
53+
this.field = field;
54+
return this;
55+
}
56+
57+
public GenericError.Builder help(Object help) {
58+
this.help = help;
59+
return this;
60+
}
61+
62+
public GenericError build() {
63+
return new GenericError(this);
64+
}
65+
66+
}
67+
68+
@Override
69+
public String toString() {
70+
StringJoiner joiner = new StringJoiner(", ", GenericError.class.getSimpleName() + "(", ")");
71+
if (message != null) joiner.add("message=" + message);
72+
if (field != null) joiner.add("field=" + field);
73+
if (help != null) joiner.add("help=" + help);
74+
return joiner.toString();
75+
}
76+
77+
}
78+

src/main/java/com/sendgrid/http/ApiKeyRestClient.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
public class ApiKeyRestClient {
1616
private final String apiKey;
17+
@Getter
1718
private final String region;
1819
@Getter
1920
private final ObjectMapper objectMapper;

src/main/java/com/sendgrid/http/Request.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public class Request {
1616
@Getter
1717
private final String url;
1818
@Getter
19+
private final String domain;
20+
@Getter
1921
private String body;
2022
@Getter
2123
private Map<String, String> headers;
@@ -33,26 +35,31 @@ public void addHeader(String key, String value) {
3335

3436
private Request(Builder builder) {
3537
this.method = builder.method;
38+
this.domain = builder.domain;
39+
this.region = builder.region;
3640
this.body = builder.body;
3741
this.headers = builder.headers;
3842

39-
String baseUrl = builder.url;
43+
String baseUrl = Utility.buildBaseUrl(domain, region, builder.endPoint);
4044
baseUrl = Utility.buildWithPathParams(baseUrl, builder.pathParams);
4145
baseUrl = Utility.buildWithQueryParams(baseUrl, builder.queryParams);
4246
this.url = baseUrl;
4347
}
4448

4549
public static class Builder {
46-
private String url;
50+
private String endPoint;
4751
private HttpMethod method;
52+
private String domain;
53+
private String region;
4854
private Map<String, String> headers = new HashMap<>();
49-
private Map<String, List<String>> queryParams = new HashMap<>();
55+
private Map<String, String> queryParams = new HashMap<>();
5056
private Map<String, String> pathParams = new HashMap<>();
5157
private String body;
5258

53-
public Builder(HttpMethod method, String url) {
59+
public Builder(HttpMethod method, String endPoint, String domain) {
5460
this.method = method;
55-
this.url = url;
61+
this.endPoint = endPoint;
62+
this.domain = domain;
5663
}
5764

5865
public Builder addPathParam(String key, String value) {
@@ -70,23 +77,27 @@ public Builder addHeaderParam(String key, String value) {
7077
* limit: If limit occurs as query param in open api spec
7178
* offset: If offset occurs as query param in open api spec
7279
* query: If there is query parameter apart from limit and offset.
73-
* It will be the responsibility of the client to build a compound query, encode it and pass it as a query parameter in the query field.
80+
* It will be the responsibility of the client to build a compound query and pass it as a query parameter in the query field.
7481
*/
7582
public Builder addQueryParam(String key, String value) {
76-
if (!queryParams.containsKey(key)) {
77-
queryParams.put(key, new ArrayList<String>());
78-
}
79-
queryParams.get(key).add(value);
83+
queryParams.put(key, value);
8084
return this;
8185
}
8286

8387
public Builder addBody(String body) {
8488
this.body = body;
8589
return this;
8690
}
91+
92+
public Builder region(String region) {
93+
this.region = region;
94+
return this;
95+
}
8796

8897
public Request build() {
8998
return new Request(this);
9099
}
91100
}
101+
102+
92103
}
Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,51 @@
11
package com.sendgrid.util;
22

3-
import com.fasterxml.jackson.core.JsonProcessingException;
4-
import com.fasterxml.jackson.databind.JsonMappingException;
5-
import com.fasterxml.jackson.databind.ObjectMapper;
6-
import com.sendgrid.exception.ApiConnectionException;
7-
import com.sendgrid.exception.ApiException;
3+
import com.sendgrid.constant.EnumConstants;
4+
import org.apache.http.client.utils.URIBuilder;
85

9-
import java.io.IOException;
10-
import java.net.URLEncoder;
11-
import java.nio.charset.StandardCharsets;
6+
import java.util.Arrays;
127
import java.util.List;
138
import java.util.Map;
14-
import java.util.StringJoiner;
159

1610
public class Utility {
17-
public static String buildWithPathParams(String path, Map<String, String> params) {
11+
12+
public static String buildBaseUrl(final String domain, final String region, final String endPoint) {
13+
List<String> availableRegions = EnumConstants.Region.getValues();
14+
StringBuilder defaultDomain = new StringBuilder(domain);
15+
if (availableRegions.contains(region)) {
16+
if (!EnumConstants.Region.GLOBAL.getValue().equals(region)) {
17+
defaultDomain.append(".");
18+
defaultDomain.append(region);
19+
}
20+
}
21+
return "https://" + defaultDomain.toString() + ".sendgrid.com" + endPoint;
22+
}
23+
public static String buildWithPathParams(String path, final Map<String, String> params) {
1824
for (Map.Entry<String, String> entry : params.entrySet()) {
1925
String placeholder = "\\{" + entry.getKey() + "\\}";
2026
path = path.replaceAll(placeholder, entry.getValue());
2127
}
2228
return path;
2329
}
2430

25-
public static String buildWithQueryParams(String path, Map<String, List<String>> queryParams) {
26-
if (queryParams.isEmpty()) {
27-
return path;
31+
public static String buildWithQueryParams(String path, final Map<String, String> queryParams) {
32+
URIBuilder builder = new URIBuilder();
33+
if (queryParams != null) {
34+
String multiValueDelimiter = "&";
35+
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
36+
String key = entry.getKey();
37+
String value = entry.getValue();
38+
39+
if (value.contains(multiValueDelimiter)) {
40+
List<String> values = Arrays.asList(value.split(multiValueDelimiter));
41+
for (String val : values) {
42+
builder.addParameter(key, val);
43+
}
44+
} else {
45+
builder.setParameter(key, value);
46+
}
47+
}
2848
}
29-
StringJoiner joiner = new StringJoiner("&");
30-
queryParams.forEach((key, values) -> {
31-
values.forEach(value -> {
32-
joiner.add(key + "=" + value); // In case all query parameter needs to be URL Encoded, encode value here.
33-
});
34-
});
35-
path = path + "?" + joiner.toString();
36-
return path;
49+
return path + builder.toString();
3750
}
3851
}

0 commit comments

Comments
 (0)