The standard HTTP Client in Java 8 is HttpURLConnection, but working with it is not so intuitively, so I have written a small helper class, that does:
- All HTTP method: GET, POST, PUT, DELETE, etc.
- Sets HTTP Request Headers
- Sets HTTP POST Body
- Read response
- Read response Body
- Read response Headers
package se.magnuskkarlsson.example.httpurlconnection;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HttpURLConnectionBuilder {
// See javax.ws.rs.core.HttpHeaders
// Body type in request
public static final String CONTENT_TYPE = "Content-Type: application/json";
// Accepted response by client
public static final String ACCEPT = "Accept";
// See javax.ws.rs.core.MediaType
// Media Type 'application/json'
public final static String APPLICATION_JSON = "application/json";
private URL url;
private String method;
private Map<String, String> headers = new HashMap<String, String>();
private String body;
public HttpURLConnectionBuilder() {
}
// ----------------------- Logic Methods -----------------------
public HttpURLConnectionBuilder get(URL url) {
return method(url, "GET");
}
public HttpURLConnectionBuilder post(URL url) {
return method(url, "POST");
}
public HttpURLConnectionBuilder put(URL url) {
return method(url, "PUT");
}
public HttpURLConnectionBuilder delete(URL url) {
return method(url, "DELETE");
}
public HttpURLConnectionBuilder method(URL url, String method) {
this.url = url;
this.method = method;
return this;
}
public HttpURLConnectionBuilder header(String name, String value) {
this.headers.put(name, value);
return this;
}
public HttpURLConnectionBuilder body(String body) {
this.body = body;
return this;
}
public HttpURLConnectionResponse send() throws IOException {
HttpURLConnection conn = (HttpURLConnection) this.url.openConnection();
// Set Request Method
conn.setRequestMethod(this.method);
// Set Request Headers
for (String name : this.headers.keySet()) {
conn.setRequestProperty(name, this.headers.get(name));
}
// Trace Log Request
System.out.println(conn.getRequestMethod() + " " + conn.getURL());
for (String key : conn.getRequestProperties().keySet()) {
System.out.println(
" >> " + key + ": " + conn.getRequestProperty(key));
}
// Set Request Body
if (this.body != null) {
conn.setDoOutput(true);
try (OutputStreamWriter output = new OutputStreamWriter(
new BufferedOutputStream(conn.getOutputStream()),
StandardCharsets.UTF_8)) {
output.write(this.body);
}
}
// Send Request and Get Response Code
int responseCode = conn.getResponseCode();
// Get Response Body
InputStream responseStream = null;
if (responseCode >= 200 && responseCode <= 299) {
responseStream = conn.getInputStream();
} else {
responseStream = conn.getErrorStream();
}
String responseBody = null;
try (BufferedReader in = new BufferedReader(new InputStreamReader(
responseStream, StandardCharsets.UTF_8))) {
StringBuilder builder = new StringBuilder();
for (String line = null; (line = in.readLine()) != null;) {
builder.append(line);
}
responseBody = builder.toString();
}
// Get Response Headers
Map<String, List<String>> responseHeaders = conn.getHeaderFields();
// Trace Log Response
System.out.println("<< " + conn.getHeaderField(null));
for (String key : conn.getHeaderFields().keySet()) {
if (key != null) {
System.out.println(
" << " + key + ": " + conn.getHeaderField(key));
}
}
return new HttpURLConnectionResponse(responseCode, responseBody,
responseHeaders);
}
// ----------------------- Helper Methods -----------------------
// ----------------------- Get and Set Methods -----------------------
}
And the response class is a simple immutable POJO.
package se.magnuskkarlsson.example.httpurlconnection;
import java.util.List;
import java.util.Map;
public class HttpURLConnectionResponse {
private final int statusCode;
private final String body;
private final Map<String, List<String>> headers;
public HttpURLConnectionResponse(int statusCode, String body,
Map<String, List<String>> headers) {
this.statusCode = statusCode;
this.body = body;
this.headers = headers;
}
// ----------------------- Logic Methods -----------------------
// ----------------------- Helper Methods -----------------------
// ----------------------- Get and Set Methods -----------------------
public int getStatusCode() {
return statusCode;
}
public String getBody() {
return body;
}
public Map<String, List<String>> getHeaders() {
return headers;
}
}
Now lets test it, with a simple REST service.
package se.magnuskkarlsson.example.httpurlconnection;
import java.util.logging.Logger;
import javax.json.Json;
import javax.json.JsonObject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
@Path("/persons")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class PersonResource {
private final Logger log = Logger.getLogger(PersonResource.class.getName());
// ----------------------- Logic Methods -----------------------
// Common Response Codes For All Requests
// 200 OK Request was successful
// 401 Unauthorized User not authenticated
// 403 Forbidden User not authorized for endpoint request, often due to
// missing security privileges
// Common Error Response Codes For GET
// 404 Not Found Resource not found
// 400 Bad Request Filter parameters provided were not valid Recommended
// Response Codes
@GET
@Path("/{personId}")
public Response getById(@PathParam("personId") String personId) {
if ("404".equals(personId)) {
JsonObject json = createProblemDetails(null, "Not Found", 404,
"Person with ID " + personId + " does not exists.", null);
return Response.status(Response.Status.NOT_FOUND).entity(json)
.build();
}
JsonObject json = Json.createObjectBuilder().add("personId", personId)
.add("name", "Magnus").build();
return Response.ok(json).build();
}
// Common Response Codes For POST
// 200 OK A custom action or processing request was successful
// 201 Created Created resource successfully
// 202 Accepted Long-running request has been accepted
// 400 Bad Request Fields were not valid or required fields were missing
@POST
public Response create(String name, @Context UriInfo uriInfo) {
log.info("name=" + name);
UriBuilder builder = uriInfo.getAbsolutePathBuilder();
builder.path("32");
// CREATED 201
return Response.created(builder.build()).build();
}
// Common Error Response Codes For PUT or PATCH
// 200 OK Updated resource successfully
// 400 Bad Request Fields were not valid or required fields were missing
// 404 Not Found Resource not found
// Common Error Response Codes For DELETE
// 204 No Content Resource deleted
// 404 Not Found Resource not found
// ----------------------- Helper Methods -----------------------
// Problem Details for HTTP APIs https://tools.ietf.org/html/rfc7807
protected JsonObject createProblemDetails(String type, String title,
int status, String detail, String instance) {
type = (type != null) ? type : "about:blank";
instance = (instance != null) ? instance : "";
return Json.createObjectBuilder().add("type", type).add("title", title)
.add("status", status).add("detail", detail)
.add("instance", instance).build();
}
// ----------------------- Get and Set Methods -----------------------
}
And now lets write a System Test for your REST service.
package se.magnuskkarlsson.example.httpurlconnection;
import static org.hamcrest.CoreMatchers.is;
import static se.magnuskkarlsson.example.httpurlconnection.HttpURLConnectionBuilder.*;
import java.net.URL;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Test;
public class HttpURLConnectionST {
@Test
public void test() throws Exception {
URL url = new URL(
"http://localhost:8080/example-java8-httpurlconnection/rest/persons/12");
HttpURLConnectionResponse response = new HttpURLConnectionBuilder()
.get(url) //
.header(CONTENT_TYPE, APPLICATION_JSON) //
.header(ACCEPT, APPLICATION_JSON) //
.send();
Assert.assertThat(response.getStatusCode(), is(200));
Assert.assertThat(response.getBody(),
is("{\"personId\":\"12\",\"name\":\"Magnus\"}"));
}
@Test
public void testNonExisting() throws Exception {
URL url = new URL(
"http://localhost:8080/example-java8-httpurlconnection/rest/persons/404");
HttpURLConnectionResponse response = new HttpURLConnectionBuilder()
.get(url) //
.header(CONTENT_TYPE, APPLICATION_JSON) //
.header(ACCEPT, APPLICATION_JSON) //
.send();
Assert.assertThat(response.getStatusCode(), is(404));
Assert.assertThat(response.getBody(),
CoreMatchers.containsString("\"title\":\"Not Found\""));
}
@Test
public void testPost() throws Exception {
URL url = new URL(
"http://localhost:8080/example-java8-httpurlconnection/rest/persons");
HttpURLConnectionResponse response = new HttpURLConnectionBuilder()
.post(url) //
.header(CONTENT_TYPE, APPLICATION_JSON) //
.header(ACCEPT, APPLICATION_JSON) //
.body("{\"name\":\"FOO\"}") //
.send();
Assert.assertThat(response.getStatusCode(), is(201));
Assert.assertThat(response.getBody(), is(""));
Assert.assertThat(response.getHeaders().get("Location").get(0),
CoreMatchers.notNullValue());
}
}
No comments:
Post a Comment