Working with HTTP or HTTPS services
A common use of the Connection API is to work with REST services over HTTP or HTTPS.
The following sections contain additional information regarding the use of the Connection
API to work with HTTP and HTTPS services.
A more general description of the Connection API can be found in
Using the Connection API.
For reference information about the http and https connection protocols
and their configuration, see HTTP and HTTPS protocols.
Invoking a simple REST service
The following example uses the Connection API and zero.core.Json to
POST a simple JSON request to a REST service and deserialize the response:
try {
// Create Connection object to POST to our target resource
Connection conn = new Connection("http://localhost:8080/myService.groovy", Connection.Operation.POST);
// Set Content-Type for request body
conn.addRequestHeader("Content-Type", "text/json; charset=\"UTF-8\"");
// Set request body (requestData is a Map representing the JSON object)
conn.setRequestBody(Json.encode(requestData));
// Send request and prepare for response
Connection.Response resp = conn.send();
// Check HTTP status code was 200
if ("200".equals(resp.getResponseStatus())) {
// Could check response Content-Type here, if necessary
// Get response body and deserialize JSON
Object resultData = Json.decode(resp.getResponseBodyAsString());
// resultData now contains deserialized JSON response
} else {
// Handle status code other than "200"
}
} catch (Exception e) {
// Handle exception
}
Working with Content-Type and character encodings
The Connection API and http and https protocol implementations
honor the content encoding specified by the charset parameter of the Content-Type
header when converting between character and binary data:
- When sending a
StringorReaderobject as the response body, the application should add aContent-Typerequest header with acharsetvalue indicating the encoding to use when writing the character data into the HTTP request. If nocharsetvalue is specified, the HTTP default encoding,ISO-8859-1, is used. - When the application requests the response body using
getResponseBodyAsString()orgetResponseBodyReader()thecharsetvalue in the response content type sent by the server is honored. If nocharsetvalue is specified, the HTTP default encoding,ISO-8859-1, is used.
The following code sample sends a text/plain string using the UTF-8 encoding
and obtains a string contain the response. The response is decoded using the response character encoding
specified by the server:
try {
// POST a text/plain body with UTF-8 encoding
Connection conn = new Connection("http://localhost:8080/myService.groovy", Connection.Operation.POST);
conn.addRequestHeader("Content-Type", "text/plain; charset=\"UTF-8\"");
conn.setRequestBody("This string can contain any Unicode character");
// Read response string, using response charset encoding sent by server
String responseString = conn.send().getResponseBodyAsString();
} catch (Exception e) {
// Handle exception
}
Uploading files to HTTP or HTTPS services
The Connection API can be used in conjunction with an instance of the
MultipartBody class to upload a file to HTTP or HTTPS services,
using the multipart/form-data content type. This can be seen in the following example:
try {
// Open input stream for image file contents
InputStream imageStream =
Connection.doGET("file:///C:/images/uploadImage.jpeg").getResponseBodyInputStream();
// Prepare multipart request body
MultipartBody multipartBody = new MultipartBody(MultipartBody.MULTIPART_FORM_DATA);
MultipartBody.Part filePart = multipartBody.add(imageStream);
filePart.setProperty(MultipartBody.CONTENT_TYPE, "image/jpeg");
filePart.setProperty(MultipartBody.CONTENT_DISPOSITION,
"form-data; name=\"myFile\"; filename=\"myFile.jpeg\"");
// POST multipart form data to HTTP service
String statusCode = Connection.doPOST("http://localhost:8080/uploadFile.groovy",
multipartBody).getResponseStatus();
// Check HTTP statusCode to confirm successful upload
} catch (Exception e) {
// Handle exception
}
The above example uses two Connection API invocations. The first uses the GET operation
and the file protocol to open an InputStream from which the contents of an image file can be
read. The second invocation uses the POST operation of the http protocol to send the image
file to the HTTP service.
The request body for the POST is an instance of
zero.core.connection.MultipartBody that contains a single part representing the file.
The http and https protocol implementations perform the appropriate encoding of the
request body and send a multipart MIME message to the HTTP service.
See the API reference for zero.core
for more information about
the zero.core.connection.MultipartBody class.
Targeting local HTTP resources
An application can use the Connection API to invoke a local endpoint relative to the current
request path, without specifying the full URL.
This mechanism can be used when Connection API is invoked within the
context of an incomming HTTP or HTTPS request.
Relative names can be specified using any Connection API method that
sets the target resource name.
For example, an application can use a relative name when constructing a new Connection
object:
Connection conn = new Connection("./myOtherScript.groovy");
If the above example code is invoked in the request handler for
http://myApp.projectzero.org:8080/contextRoot/someFolder/myScript.groovy,
the resulting connection targets
http://myApp.projectzero.org:8080/contextRoot/someFolder/myOtherScript.groovy.
Moreover, the result of conn.getResource() is the full target
resource name and not ./myOtherScript.groovy
The following prefixes can be used to indicate a relative target resource name:
| Prefix | Description |
|---|---|
./ |
Relative to folder containing current request handler, as indicated by /request/path. |
../ |
Relative to parent of folder containing current request handler, as indicated by /request/path. |
~/ |
Relative to the application context root. |
Any target resource name that does not begin with one of the prefixes indicated above
is interpreted as an absolute resource name.
In particular, resources starting with / are not resolved relative to the current request.
Basic authentication and connection configuration
The http and https protocol implementations support a number of protocol
configuration parameters, such as HTTPS trust store configuration and request timeout values.
Amongst these are the userid and password protocol configuration parameters,
which can be used to automatically include a basic authentication header in the outgoing request.
The following example uses the setProtocolConfiguration() method to
set programmatically the basic authentication credentials for the request sent
to the HTTP service:
try {
// Create Connection object (default operation is GET)
Connection conn = new Connection("http://localhost:8080/myService.groovy");
// Set parameters for basic authentication
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("userid", "user1");
parameters.put("password", "password1");
conn.setProtocolConfiguration("http", parameters);
// Send request and prepare for response
Connection.Response resp = conn.send();
// Work with the response
} catch (Exception e) {
// Handle exception
}
For circumstances in which it is not be desirable to hard code protocol parameters in
the application logic, the connection infrastructure enables protocol configuration to
be specified in zero.config. For example, the following connection
destination configuration specifies the basic authentication parameters for all requests
to the http://localhost:8080/myService.groovy service:
/config/connection/destinations += {
"http://localhost:8080/myService.groovy" : {
"connection" : {
"protocol" : "http",
"config" : {
"userid" : "user1",
"password" : "password1"
}
}
}
}
With the above destination configuration in place, the application can send a request to the service without hard coding the protocol configuration:
try {
// Create Connection object (default operation is GET)
Connection conn = new Connection("http://localhost:8080/myService.groovy");
// Send request and prepare for response
Connection.Response resp = conn.send();
// Work with the response
} catch (Exception e) {
// Handle exception
}
Connection handlers can also set protocol configuration. For example, a connection handler
could dynamically select a userid and password value for an
outgoing request. As with specifying the configuration in the destination configuration,
using a connection handler would avoid any modification of the application logic but would
also avoid the restriction of a fixed value in zero.config.
For more information about the mechanisms available for protocol configuration,
see Configuring protocols.
For more information about the configuration of the http and https connection protocols,
including the configuration of the trust store and key store for HTTPS communications,
see HTTP and HTTPS protocols.
Working with HTTP cookies
The http and https protocol implementations
can be used to send and receive HTTP cookies.
Cookies can be read from responses and set on subsequent requests using either the
Connection API or by writing a connection handler.
- The
httpandhttpsprotocol implementations filter the cookies received from the remote server. If the server attempts to set a cookie that does not match the requested resource it will not be included in the list of responseCookievalues presented to the application or connection handler. However, the there is no filtering of cookies on outbound requests. As such, it is the developers responsibility verify that only desired cookies are set on outbound requests.
Managing cookies using the Connection API
The Connection.Response class provides several methods by which the application
can obtain cookies sent with the response:
-
List<Cookie> getResponseCookies() -
Set<String> getResponseCookieNames() -
List<Cookie> getResponseCookie(String name)
See the API reference for zero.core
for more information about these methods.
The Connection class provides method that allow the application to send
cookies that were received with a previous response:
-
void addRequestCookie(Cookie cookie) -
void addRequestCookies(List<Cookie> cookies) -
void setRequestCookies(List<Cookie> cookies) -
List<Cookie> removeRequestCookie(String name)
See the API reference for zero.core
for more information about these methods.
In the following example Groovy code, the Connection API is used to make two
requests to the same server, with the cookies received with the first response being
sent with the second request:
try {
// Send first request
Connection conn1 = new Connection("http://localhost:8080/myService.groovy");
Connection.Response resp1 = conn1.send();
// Collect cookies from first response
List<zero.core.cookie.Cookie> cookies = resp1.getResponseCookies();
// Work with remainder of first response
// Send second request, including cookies from first response
Connection conn2 = new Connection("http://localhost:8080/myService.groovy");
conn2.setRequestCookies(cookies);
Connection.Response resp2 = conn2.send();
// Work with second response
} catch (Exception e) {
// Handle exception
}
Managing cookies using a connection handler
Request and response cookies are made available in the /connection zone and
so can be manipulated by connection handlers. A connection handler can be used to manage the
cookies for all requests sent to a connection destionation; avoiding additional complication in
application flows and scripts.
For example, the response phase of a connection handler could collect the list of cookies
sent from a service and store them in the /user zone. The request phase of the
connection handler could look for these stored cookies and add them to requests sent to the service.
For more information about writing a connection handler, see
Creating a connection handler.