-
Notifications
You must be signed in to change notification settings - Fork 17
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
feat(java): add requestOptions
#487
Changes from all commits
d416640
90266ee
9345dd9
ad0ff62
fc4ce88
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package com.algolia.utils; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import javax.annotation.Nonnull; | ||
|
||
/** | ||
* Request options are used to pass extra parameters, headers, timeout to the request. Parameters | ||
* set in the request option will override default parameter. | ||
*/ | ||
public class RequestOptions { | ||
|
||
private final Map<String, String> headers = new HashMap<String, String>(); | ||
private final Map<String, String> queryParams = new HashMap<String, String>(); | ||
private Integer timeout = null; | ||
|
||
public RequestOptions addExtraHeader( | ||
@Nonnull String key, | ||
@Nonnull String value | ||
) { | ||
headers.put(key, value); | ||
return this; | ||
} | ||
|
||
public RequestOptions addExtraQueryParameters( | ||
@Nonnull String key, | ||
@Nonnull String value | ||
) { | ||
queryParams.put(key, value); | ||
return this; | ||
} | ||
|
||
public Map<String, String> getExtraHeaders() { | ||
return headers; | ||
} | ||
|
||
public Map<String, String> getExtraQueryParams() { | ||
return queryParams; | ||
} | ||
|
||
public Integer getTimeout() { | ||
return timeout; | ||
} | ||
|
||
public RequestOptions setTimeout(Integer timeout) { | ||
this.timeout = timeout; | ||
return this; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return ( | ||
"RequestOptions{" + | ||
"headers=" + | ||
headers + | ||
", queryParams=" + | ||
queryParams + | ||
'\'' + | ||
'}' | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -240,13 +240,13 @@ export function createTransporter({ | |
cacheable: baseRequestOptions?.cacheable, | ||
timeout: baseRequestOptions?.timeout, | ||
queryParameters: { | ||
...baseRequestOptions?.queryParameters, | ||
...methodOptions.queryParameters, | ||
...baseRequestOptions?.queryParameters, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was wrong, parameters from |
||
}, | ||
headers: { | ||
Accept: 'application/json', | ||
...baseRequestOptions?.headers, | ||
...methodOptions.headers, | ||
...baseRequestOptions?.headers, | ||
}, | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -4,6 +4,7 @@ import com.algolia.utils.Requester; | |||||||||||||||||||||
import com.algolia.exceptions.*; | ||||||||||||||||||||||
import com.algolia.utils.UserAgent; | ||||||||||||||||||||||
import com.algolia.utils.JSON; | ||||||||||||||||||||||
import com.algolia.utils.RequestOptions; | ||||||||||||||||||||||
|
||||||||||||||||||||||
import okhttp3.*; | ||||||||||||||||||||||
import okhttp3.internal.http.HttpMethod; | ||||||||||||||||||||||
|
@@ -27,8 +28,7 @@ public class ApiClient { | |||||||||||||||||||||
private boolean debugging = false; | ||||||||||||||||||||||
private Map<String, String> defaultHeaderMap = new HashMap<String, String>(); | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
private String appId, apiKey; | ||||||||||||||||||||||
private String contentType; | ||||||||||||||||||||||
|
||||||||||||||||||||||
private DateFormat dateFormat; | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
@@ -38,6 +38,8 @@ public class ApiClient { | |||||||||||||||||||||
* Constructor for ApiClient with custom Requester | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
public ApiClient(String appId, String apiKey, Requester requester, String clientName, UserAgent.Segment[] segments) { | ||||||||||||||||||||||
this.contentType = "application/json"; | ||||||||||||||||||||||
|
||||||||||||||||||||||
UserAgent ua = new UserAgent("{{packageVersion}}"); | ||||||||||||||||||||||
ua.addSegment(new UserAgent.Segment(clientName, "{{packageVersion}}")); | ||||||||||||||||||||||
if(segments != null) { | ||||||||||||||||||||||
|
@@ -47,8 +49,11 @@ public class ApiClient { | |||||||||||||||||||||
} | ||||||||||||||||||||||
setUserAgent(ua.toString()); | ||||||||||||||||||||||
|
||||||||||||||||||||||
this.appId = appId; | ||||||||||||||||||||||
this.apiKey = apiKey; | ||||||||||||||||||||||
defaultHeaderMap.put("X-Algolia-Application-Id", appId); | ||||||||||||||||||||||
defaultHeaderMap.put("X-Algolia-API-Key", apiKey); | ||||||||||||||||||||||
defaultHeaderMap.put("Accept", this.contentType); | ||||||||||||||||||||||
defaultHeaderMap.put("Content-Type", this.contentType); | ||||||||||||||||||||||
|
||||||||||||||||||||||
this.requester = requester; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
@@ -189,22 +194,6 @@ public class ApiClient { | |||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
/** | ||||||||||||||||||||||
* Check if the given MIME is a JSON MIME. | ||||||||||||||||||||||
* JSON MIME examples: | ||||||||||||||||||||||
* application/json | ||||||||||||||||||||||
* application/json; charset=UTF8 | ||||||||||||||||||||||
* APPLICATION/JSON | ||||||||||||||||||||||
* application/vnd.company+json | ||||||||||||||||||||||
* "* / *" is also default to JSON | ||||||||||||||||||||||
* @param mime MIME (Multipurpose Internet Mail Extensions) | ||||||||||||||||||||||
* @return True if the given MIME is JSON, false otherwise. | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
public static boolean isJsonMime(String mime) { | ||||||||||||||||||||||
String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"; | ||||||||||||||||||||||
return mime != null && (mime.matches(jsonMime) || mime.equals("*/*")); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
/** | ||||||||||||||||||||||
* Escape the given string to be used as URL query value. | ||||||||||||||||||||||
* | ||||||||||||||||||||||
|
@@ -220,29 +209,23 @@ public class ApiClient { | |||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
/** | ||||||||||||||||||||||
* Serialize the given Java object into request body according to the object's | ||||||||||||||||||||||
* class and the request Content-Type. | ||||||||||||||||||||||
* Serialize the given Java object into request body according to the object's class and the | ||||||||||||||||||||||
* request Content-Type. | ||||||||||||||||||||||
* | ||||||||||||||||||||||
* @param obj The Java object | ||||||||||||||||||||||
* @param contentType The request Content-Type | ||||||||||||||||||||||
* @return The serialized request body | ||||||||||||||||||||||
* @throws AlgoliaRuntimeException If fail to serialize the given object | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
public RequestBody serialize(Object obj, String contentType) throws AlgoliaRuntimeException { | ||||||||||||||||||||||
if (obj instanceof byte[]) { | ||||||||||||||||||||||
// Binary (byte array) body parameter support. | ||||||||||||||||||||||
return RequestBody.create((byte[]) obj, MediaType.parse(contentType)); | ||||||||||||||||||||||
} else if (isJsonMime(contentType)) { | ||||||||||||||||||||||
String content; | ||||||||||||||||||||||
if (obj != null) { | ||||||||||||||||||||||
content = JSON.serialize(obj); | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
content = null; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
return RequestBody.create(content, MediaType.parse(contentType)); | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
throw new AlgoliaRuntimeException("Content type \"" + contentType + "\" is not supported"); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
public RequestBody serialize(Object obj) throws AlgoliaRuntimeException { | ||||||||||||||||||||||
String content; | ||||||||||||||||||||||
|
||||||||||||||||||||||
if (obj != null) { | ||||||||||||||||||||||
content = JSON.serialize(obj); | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
content = null; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
return RequestBody.create(content, MediaType.parse(this.contentType)); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
/** | ||||||||||||||||||||||
|
@@ -286,11 +269,12 @@ public class ApiClient { | |||||||||||||||||||||
* @param queryParams The query parameters | ||||||||||||||||||||||
* @param body The request body object | ||||||||||||||||||||||
* @param headerParams The header parameters | ||||||||||||||||||||||
* @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions. | ||||||||||||||||||||||
* @return The HTTP call | ||||||||||||||||||||||
* @throws AlgoliaRuntimeException If fail to serialize the request body object | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
public Call buildCall(String path, String method, Map<String, String> queryParams, Object body, Map<String, String> headerParams) throws AlgoliaRuntimeException { | ||||||||||||||||||||||
Request request = buildRequest(path, method, queryParams, body, headerParams); | ||||||||||||||||||||||
public Call buildCall(String path, String method, Map<String, String> queryParams, Object body, Map<String, String> headerParams, RequestOptions requestOptions) throws AlgoliaRuntimeException { | ||||||||||||||||||||||
Request request = buildRequest(path, method, queryParams, body, headerParams, requestOptions); | ||||||||||||||||||||||
|
||||||||||||||||||||||
return requester.newCall(request); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
@@ -303,37 +287,38 @@ public class ApiClient { | |||||||||||||||||||||
* @param queryParams The query parameters | ||||||||||||||||||||||
* @param body The request body object | ||||||||||||||||||||||
* @param headerParams The header parameters | ||||||||||||||||||||||
* @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions. | ||||||||||||||||||||||
* @return The HTTP request | ||||||||||||||||||||||
* @throws AlgoliaRuntimeException If fail to serialize the request body object | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
public Request buildRequest(String path, String method, Map<String, String> queryParams, Object body, Map<String, String> headerParams) throws AlgoliaRuntimeException { | ||||||||||||||||||||||
headerParams.put("X-Algolia-Application-Id", this.appId); | ||||||||||||||||||||||
headerParams.put("X-Algolia-API-Key", this.apiKey); | ||||||||||||||||||||||
headerParams.put("Accept", "application/json"); | ||||||||||||||||||||||
headerParams.put("Content-Type", "application/json"); | ||||||||||||||||||||||
|
||||||||||||||||||||||
String contentType = "application/json"; | ||||||||||||||||||||||
headerParams.put("Accept", contentType); | ||||||||||||||||||||||
headerParams.put("Content-Type", contentType); | ||||||||||||||||||||||
|
||||||||||||||||||||||
final String url = buildUrl(path, queryParams); | ||||||||||||||||||||||
public Request buildRequest(String path, String method, Map<String, String> queryParams, Object body, Map<String, String> headerParams, RequestOptions requestOptions) throws AlgoliaRuntimeException { | ||||||||||||||||||||||
boolean hasRequestOptions = requestOptions != null; | ||||||||||||||||||||||
final String url = buildUrl( | ||||||||||||||||||||||
path, | ||||||||||||||||||||||
queryParams, | ||||||||||||||||||||||
hasRequestOptions ? requestOptions.getExtraQueryParams() : null | ||||||||||||||||||||||
); | ||||||||||||||||||||||
final Request.Builder reqBuilder = new Request.Builder().url(url); | ||||||||||||||||||||||
processHeaderParams(headerParams, reqBuilder); | ||||||||||||||||||||||
|
||||||||||||||||||||||
processHeaderParams( | ||||||||||||||||||||||
headerParams, | ||||||||||||||||||||||
hasRequestOptions ? requestOptions.getExtraHeaders() : null, | ||||||||||||||||||||||
reqBuilder | ||||||||||||||||||||||
); | ||||||||||||||||||||||
|
||||||||||||||||||||||
RequestBody reqBody; | ||||||||||||||||||||||
if (!HttpMethod.permitsRequestBody(method)) { | ||||||||||||||||||||||
reqBody = null; | ||||||||||||||||||||||
} else if (body == null) { | ||||||||||||||||||||||
if ("DELETE".equals(method)) { | ||||||||||||||||||||||
// allow calling DELETE without sending a request body | ||||||||||||||||||||||
reqBody = null; | ||||||||||||||||||||||
// allow calling DELETE without sending a request body | ||||||||||||||||||||||
reqBody = null; | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
// use an empty request body (for POST, PUT and PATCH) | ||||||||||||||||||||||
reqBody = RequestBody.create("", MediaType.parse(contentType)); | ||||||||||||||||||||||
// use an empty request body (for POST, PUT and PATCH) | ||||||||||||||||||||||
reqBody = RequestBody.create("", MediaType.parse(this.contentType)); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
reqBody = serialize(body, contentType); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
reqBody = serialize(body); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
return reqBuilder.method(method, reqBody).build(); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
@@ -343,48 +328,80 @@ public class ApiClient { | |||||||||||||||||||||
* | ||||||||||||||||||||||
* @param path The sub path | ||||||||||||||||||||||
* @param queryParams The query parameters | ||||||||||||||||||||||
* @param extraQueryParams The query parameters, coming from the requestOptions | ||||||||||||||||||||||
* @return The full URL | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
public String buildUrl(String path, Map<String, String> queryParams) { | ||||||||||||||||||||||
final StringBuilder url = new StringBuilder(); | ||||||||||||||||||||||
public String buildUrl(String path, Map<String, String> queryParams, Map<String, String> extraQueryParams) { | ||||||||||||||||||||||
StringBuilder url = new StringBuilder(); | ||||||||||||||||||||||
|
||||||||||||||||||||||
//The real host will be assigned by the retry strategy | ||||||||||||||||||||||
url.append("http://temp.path").append(path); | ||||||||||||||||||||||
|
||||||||||||||||||||||
if (queryParams != null && !queryParams.isEmpty()) { | ||||||||||||||||||||||
// support (constant) query string in `path`, e.g. "/posts?draft=1" | ||||||||||||||||||||||
String prefix = path.contains("?") ? "&" : "?"; | ||||||||||||||||||||||
for (Entry<String, String> param : queryParams.entrySet()) { | ||||||||||||||||||||||
if (param.getValue() != null) { | ||||||||||||||||||||||
if (prefix != null) { | ||||||||||||||||||||||
url.append(prefix); | ||||||||||||||||||||||
prefix = null; | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
url.append("&"); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
String value = parameterToString(param.getValue()); | ||||||||||||||||||||||
url.append(escapeString(param.getKey())).append("=").append(escapeString(value)); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
url = parseQueryParameters(path, url, queryParams); | ||||||||||||||||||||||
url = parseQueryParameters(path, url, extraQueryParams); | ||||||||||||||||||||||
|
||||||||||||||||||||||
return url.toString(); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
/** | ||||||||||||||||||||||
* Parses the given map of Query Parameters to a given URL. | ||||||||||||||||||||||
* | ||||||||||||||||||||||
* @param path The sub path | ||||||||||||||||||||||
* @param url The url to add queryParams to | ||||||||||||||||||||||
* @param queryParams The query parameters | ||||||||||||||||||||||
* @return The URL | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
public StringBuilder parseQueryParameters( | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As the logic was duplicated for both map I've used this, it seems to work but not a fan of the implem |
||||||||||||||||||||||
String path, | ||||||||||||||||||||||
StringBuilder url, | ||||||||||||||||||||||
Map<String, String> queryParams | ||||||||||||||||||||||
) { | ||||||||||||||||||||||
if (queryParams != null && !queryParams.isEmpty()) { | ||||||||||||||||||||||
// support (constant) query string in `path`, e.g. "/posts?draft=1" | ||||||||||||||||||||||
String prefix = path.contains("?") ? "&" : "?"; | ||||||||||||||||||||||
for (Entry<String, String> param : queryParams.entrySet()) { | ||||||||||||||||||||||
if (param.getValue() != null) { | ||||||||||||||||||||||
if (prefix != null) { | ||||||||||||||||||||||
url.append(prefix); | ||||||||||||||||||||||
prefix = null; | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
url.append("&"); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
Comment on lines
+364
to
369
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about something like...
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I copied the actual logic to avoid introducing unrelated changes, I don't really know the edge cases possible here D: |
||||||||||||||||||||||
String value = parameterToString(param.getValue()); | ||||||||||||||||||||||
url | ||||||||||||||||||||||
.append(escapeString(param.getKey())) | ||||||||||||||||||||||
.append("=") | ||||||||||||||||||||||
.append(escapeString(value)); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
return url.toString(); | ||||||||||||||||||||||
return url; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
/** | ||||||||||||||||||||||
* Set header parameters to the request builder, including default headers. | ||||||||||||||||||||||
* | ||||||||||||||||||||||
* @param headerParams Header parameters in the form of Map | ||||||||||||||||||||||
* @param extraHeaderParams Header parameters in the form of Map, coming from RequestOptions | ||||||||||||||||||||||
* @param reqBuilder Request.Builder | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
public void processHeaderParams(Map<String, String> headerParams, Request.Builder reqBuilder) { | ||||||||||||||||||||||
public void processHeaderParams(Map<String, String> headerParams, Map<String, String> extraHeaderParams, Request.Builder reqBuilder) { | ||||||||||||||||||||||
for (Entry<String, String> param : headerParams.entrySet()) { | ||||||||||||||||||||||
reqBuilder.header(param.getKey(), parameterToString(param.getValue())); | ||||||||||||||||||||||
reqBuilder.header(param.getKey(), parameterToString(param.getValue())); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
for (Entry<String, String> header : defaultHeaderMap.entrySet()) { | ||||||||||||||||||||||
if (!headerParams.containsKey(header.getKey())) { | ||||||||||||||||||||||
reqBuilder.header(header.getKey(), parameterToString(header.getValue())); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
if (!headerParams.containsKey(header.getKey())) { | ||||||||||||||||||||||
reqBuilder.header(header.getKey(), parameterToString(header.getValue())); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
if (extraHeaderParams != null) { | ||||||||||||||||||||||
for (Entry<String, String> header : extraHeaderParams.entrySet()) { | ||||||||||||||||||||||
reqBuilder.header( | ||||||||||||||||||||||
header.getKey(), | ||||||||||||||||||||||
parameterToString(header.getValue()) | ||||||||||||||||||||||
); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file copied from the current client implementation: https://github.com/algolia/algoliasearch-client-java-2/blob/master/algoliasearch-core/src/main/java/com/algolia/search/models/RequestOptions.java