com.ibm.watson.developer_cloud.http1.RequestBuilder Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2017 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.ibm.watson.developer_cloud.http1;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.JsonObject;
import com.ibm.watson.developer_cloud.http.HttpHeaders;
import com.ibm.watson.developer_cloud.http.HttpMediaType;
import com.ibm.watson.developer_cloud.http.InputStreamRequestBody;
import com.ibm.watson.developer_cloud.http.NameValue;
import com.ibm.watson.developer_cloud.service.WatsonService;
import com.ibm.watson.developer_cloud.util.GsonSingleton;
import com.ibm.watson.developer_cloud.util.StringHelper;
import com.ibm.watson.developer_cloud.util.Validator;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
/**
* Convenience class for constructing HTTP/HTTPS requests.
*/
public class RequestBuilder {
private enum HTTPMethod {
DELETE, GET, POST, PUT, PATCH, HEAD
}
/**
* The DELETE method requests that the origin server delete the resource identified by the Request-URI.
*
* @param url the URL
*
* @return this
*/
public static RequestBuilder delete(HttpUrl url) {
return new RequestBuilder(HTTPMethod.DELETE, url);
}
/**
* The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.
*
* @param url the URL
*
* @return this
*/
public static RequestBuilder get(HttpUrl url) {
return new RequestBuilder(HTTPMethod.GET, url);
}
/**
* The POST request method is designed to request that a web server accept the data enclosed in the request
* message's body for storage. It is often used when uploading a file or submitting a completed web form.
*
* @param url the URL
*
* @return this
*/
public static RequestBuilder post(HttpUrl url) {
return new RequestBuilder(HTTPMethod.POST, url);
}
/**
* The PUT method requests that the enclosed entity be stored under the supplied Request-URI.
*
* @param url the URL
*
* @return this
*/
public static RequestBuilder put(HttpUrl url) {
return new RequestBuilder(HTTPMethod.PUT, url);
}
/**
* The PUT method requests that the enclosed entity be stored under the supplied Request-URI.
*
* @param url the URL
*
* @return this
*/
public static RequestBuilder patch(HttpUrl url) {
return new RequestBuilder(HTTPMethod.PATCH, url);
}
/**
* The HEAD method means retrieve the headers for the resource identified by the Request-URI.
*
* @param url the URL
*
* @return this
*/
public static RequestBuilder head(HttpUrl url) {
return new RequestBuilder(HTTPMethod.HEAD, url);
}
/**
* Creates a properly encoded HttpUrl object with no path parameters.
*
* @param endPoint the API end point
* @param pathSegments the path segments for a specific API call
* @return the HttpUrl object
*/
public static HttpUrl constructHttpUrl(String endPoint, String[] pathSegments) {
HttpUrl.Builder httpUrlBuilder = HttpUrl.parse(endPoint).newBuilder();
for (String segment : pathSegments) {
httpUrlBuilder.addPathSegments(segment);
}
return httpUrlBuilder.build();
}
/**
* Creates a properly encoded HttpUrl object with path parameters.
*
* @param endPoint the API end point
* @param pathSegments the path segments for a specific API call
* @param pathParameters the path parameters for a specific API call
* @return the HttpUrl object
*/
public static HttpUrl constructHttpUrl(String endPoint, String[] pathSegments, String[] pathParameters) {
HttpUrl.Builder httpUrlBuilder = HttpUrl.parse(endPoint).newBuilder();
for (int i = 0; i < pathSegments.length; i++) {
httpUrlBuilder.addPathSegments(pathSegments[i]);
if (i < pathParameters.length) {
httpUrlBuilder.addPathSegment(pathParameters[i]);
}
}
return httpUrlBuilder.build();
}
private RequestBody body;
private HttpUrl httpUrl;
private final List formParams = new ArrayList();
private final List headers = new ArrayList();
private final HTTPMethod method;
private final List queryParams = new ArrayList();
/**
* Instantiates a new request.
*
* @param method the method, PUT, POST, GET or DELETE
* @param url the request URL
*/
private RequestBuilder(HTTPMethod method, HttpUrl url) {
this.method = method;
if (url == null) {
throw new IllegalArgumentException("url cannot be null");
}
this.httpUrl = url;
}
/**
* Adds a key/value pair.
*
*
*
* Request r = new Request.get("https://foo.bar").add("singleParam", "value")
* .add("multiParam", new String[] { "1", "2", "3" })
* .add("singleParamWithOutValue", null);
*
*
*
* @param params the parameters
* @param name the parameter name
* @param value the value to set, will be obtained via {@link String#valueOf(boolean)}. If null, only the parameter
* is set. It can also be a collection or array, in which case all elements are added as query parameters
*
* @return this
*/
private RequestBuilder add(List params, String name, Object value) {
if (value instanceof Iterable) {
for (final Object o : (Iterable) value) {
addParam(params, name, o);
}
} else if (value instanceof Object[]) {
for (final Object o : (Object[]) value) {
addParam(params, name, o);
}
} else {
addParam(params, name, value);
}
return this;
}
/**
* Adds the name, value par to the parameter list as BasicNameValue.
*
* @param params the parameter list
* @param name the parameter name
* @param value the parameter value
*/
private void addParam(List params, String name, Object value) {
params.add(new NameValue(name, value == null ? null : String.valueOf(value)));
}
/**
* Builds the.
*
* @return the request
*/
public Request build() {
final Request.Builder builder = new Request.Builder();
// URL
builder.url(toUrl());
if (method == HTTPMethod.GET || method == HTTPMethod.HEAD) {
Validator.isNull(body, "cannot send a RequestBody in a GET or HEAD request");
} else if (!formParams.isEmpty()) {
// The current behaviour of the RequestBuilder is to replace the body when formParams is
// present
final FormBody.Builder formBody = new FormBody.Builder();
for (final NameValue param : formParams) {
final String value = param.getValue() != null ? param.getValue() : "";
formBody.add(param.getName(), value);
}
body = formBody.build();
} else if (body == null) {
// POST/PUT require a body so send an empty body if the actual is null
// DELETE allows an empty request body
body = RequestBody.create(null, new byte[0]);
}
builder.method(method.name(), body);
// accept application/json by default
builder.header(HttpHeaders.ACCEPT, HttpMediaType.APPLICATION_JSON);
for (final NameValue header : headers) {
builder.header(header.getName(), header.getValue());
}
return builder.build();
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "RequestBuilder [method=" + method + ", formParams=" + formParams + ", headers=" + headers
+ ", queryParams=" + queryParams + ", httpUrl=" + httpUrl.toString() + "]";
}
/**
* Return the request url including query parameters.
*
* @return the string
*/
private String toUrl() {
final HttpUrl.Builder builder = httpUrl.newBuilder();
for (final NameValue param : queryParams) {
builder.addQueryParameter(param.getName(), param.getValue());
}
return builder.build().uri().toString();
}
/**
* Adds a name-value par to a given list.
*
* @param params a list of parameters
* @param args a list of arguments
*
* @return this
*/
private RequestBuilder with(List params, Object... args) {
if (args != null) {
Validator.isTrue((args.length % 2) == 0, "need even number of arguments");
for (int i = 0; i < args.length; i += 2) {
add(params, args[i].toString(), args[i + 1]);
}
}
return this;
}
/**
* Sets the body.
*
* @param body the body
* @return the request builder
*/
public RequestBuilder body(RequestBody body) {
this.body = body;
return this;
}
/**
* Sets the string content to the request (used with POST/PUT). This will encapsulate the string into a
* {@link RequestBody} encoded with UTF-8
*
* @param content the content to POST/PUT
* @param contentType the HTTP contentType to use.
*
* @return this
*/
public RequestBuilder bodyContent(String content, String contentType) {
return body(RequestBody.create(MediaType.parse(contentType), content));
}
/**
* Sets the file content (InputStream) to the request (used with POST/PUT).
*
* @param stream the InputStream to read the request body content from
* @param contentType the contentType associated with the data read from the InputStream
* @return this
*/
public RequestBuilder bodyContent(InputStream stream, String contentType) {
return body(InputStreamRequestBody.create(MediaType.parse(contentType), stream));
}
/**
* Sets the request body content from one of three different sources, based on the content type.
*
* @param contentType
* the value of the "Content-Type" header associated with the outgoing request
* @param jsonContent
* the body content to be used if the content type indicates JSON
* @param jsonPatchContent
* the body content to be used if the content type indicates JsonPatch
* @param nonJsonContent
* the body content to be used if the content type indicates non-JSON content
* @return this
*/
public RequestBuilder bodyContent(String contentType, Object jsonContent, Object jsonPatchContent,
InputStream nonJsonContent) {
if (contentType != null) {
if (WatsonService.isJsonMimeType(contentType)) {
this.bodyContent(
GsonSingleton.getGson().toJsonTree(jsonContent).getAsJsonObject().toString(), contentType);
} else if (WatsonService.isJsonPatchMimeType(contentType)) {
this.bodyContent(
GsonSingleton.getGson().toJsonTree(jsonPatchContent).getAsJsonObject().toString(), contentType);
} else {
this.bodyContent(nonJsonContent, contentType);
}
}
return this;
}
/**
* Sets the request body content from one of three different sources, based on the content type.
*
* @param contentType
* the value of the "Content-Type" header associated with the outgoing request
* @param jsonContent
* the body content to be used if the content type indicates JSON
* @param jsonPatchContent
* the body content to be used if the content type indicates JsonPatch
* @param nonJsonContent
* the body content to be used if the content type indicates non-JSON content
* @return this
*/
public RequestBuilder bodyContent(String contentType, Object jsonContent, Object jsonPatchContent,
String nonJsonContent) {
InputStream nonJson = null;
if (nonJsonContent != null) {
nonJson = StringHelper.toInputStream(nonJsonContent);
}
return bodyContent(contentType, jsonContent, jsonPatchContent, nonJson);
}
/**
* Adds a JSON content to the request (used with POST/PUT). This will encapsulate the json into a
* {@link RequestBody} encoded with UTF-8 and use {@code "application/json"} as Content-Type
*
* @param json the JsonObject json
*
* @return this
*/
public RequestBuilder bodyJson(JsonObject json) {
return bodyContent(json.toString(), HttpMediaType.APPLICATION_JSON);
}
/**
* Adds a JSON content to the request (used with POST/PUT/PATCH). This will encapsulate the json into a
* {@link RequestBody} encoded with UTF-8 and use {@code "application/json"} as Content-Type
*
* @param json the JsonObject json
* @param mediaType the contentType value
*
* @return this
*/
public RequestBuilder bodyJson(JsonObject json, String mediaType) {
return bodyContent(json.toString(), mediaType);
}
/**
* Adds form parameters.
*
* @param args a list of name-value form parameters
*
* @return this
*/
public RequestBuilder form(Object... args) {
return with(formParams, args);
}
/**
* Adds header parameters.
*
* @param args a list of name-value headers
*
* @return this
*/
public RequestBuilder header(Object... args) {
return with(headers, args);
}
/**
* Adds query parameters.
*
* @param args a list of name-value query parameters
*
* @return this
*/
public RequestBuilder query(Object... args) {
return with(queryParams, args);
}
}