AIAIO: Our Blog

AIAIO: Our Blog

The pulse and reviews of Alexander Interactive

Posts Tagged ‘Apache Commons’

A Simple Java REST Client with Apache Commons HttpClient

I recently needed to build a RESTful web service client for my Java application. I wanted something simple and I had a particular set of requirements I wanted to code around (like being able to return the original request parameters along with the response) so the leaner the the actual client the better. After a little research I decided to go with a solution built on Apache Commons HttpClient which provides a rich set of abstractions for client side http interactions. I like HttpClient because it provides a higher and more functional level of abstraction than underlying java.net classes but at the same time allows you to code around whatever Http idioms you want (simple request/response, conversational services, data submission etc.) without alot of bridge code like annotations or library specific interface implementations.

Since I needed to both asynchronously POST data to a restful endpoint as well as perform GET request against another endpoint,  I abstracted all of the parameter bundling and message sending into a single processRequest() method instead of implementing separate post/get code. I also standardized the return type to a Map containing the objects I needed for my app e.g. the request parameters, the actual response and the HTTP response code (REQUEST_PARAMS, RESPONSE_BODY and RESPONSE_STATUS respectively):

processRequest():

public Map<String, Object> processRequest(String serviceUrl,
                        String sendMethod, Map<String, String> params)
{
                if (StringUtils.isBlank(serviceUrl)) {
                    throw new AiServiceException("Service URL is required");
                }
                // Essentially return a new HttpClient(), but can be pulled from Spring context
                HttpClient httpclient = getHttpClient();
                HttpMethod method = getHttpMethodFromString(sendMethod);//See Details Below
                method.setPath(serviceUrl);
                httpclient.getParams().setParameter("http.protocol.version",HttpVersion.HTTP_1_1);
                httpclient.getParams().setParameter("http.socket.timeout", Integer.valueOf(responseTimeOut));
                httpclient.getParams().setParameter("http.protocol.content-charset",charSet);
                setRequestParams(method, params);
                HashMap<String, Object> responseObject = new HashMap<String, Object>();
                try {
                        int responseCode = httpclient.executeMethod(method);
                        String respBody=getResponseBody(method);// See details Below
                        responseObject.put(REQUEST_PARAMS, params);
                        responseObject.put(RESPONSE_BODY, respBody);
                        responseObject.put(RESPONSE_STATUS, responseCode);
                        return responseObject;
                } catch (Exception e) {
                        logger.error("Error Sending REST Request [URL:"+serviceUrl+",METHOD:"+sendMethod+",PARAMS:"+params+"]", e);
                        throw new AiServiceException(e);
                } finally {
                        method.releaseConnection();
                }
        }

To make this work I  wrote a method parse an actual HttpMethod Object from a given string:
getHttpMethodFromString():

private HttpMethod getHttpMethodFromString(String methodString) {
		if (StringUtils.isNotBlank(methodString)) {
			org.springframework.http.HttpMethod parsedMethod = org.springframework.http.HttpMethod
					.valueOf(methodString.toUpperCase());
			switch (parsedMethod) {//Add other methods as needed PUT, DELETE etc.
			case GET:
				return new GetMethod();
			case POST:
				return new PostMethod();
			default:
				return new GetMethod();
			}
		}
		return new GetMethod();
	}

Finally I needed to make sure to read the entire response before returning it to caller:
getResponseBody():

protected String getResponseBody(HttpMethod method){
		//Ensure we have read entire response body by reading from buffered stream
		if(method!=null&& method.hasBeenUsed()){
			BufferedReader in=null;
			StringWriter stringOut= new StringWriter();
			BufferedWriter dumpOut = new BufferedWriter(stringOut,8192);
			try {
				 in=new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
				String line = "";
				while ((line = in.readLine()) != null) {
					dumpOut.write(line);
					dumpOut.newLine();
				}
			} catch (IOException e) {
				logger.error("Error Reading Response Stream",e);
				throw new AiServiceException(e);
			}finally{
				try {
					dumpOut.flush();
					dumpOut.close();
					if(in!=null)
						in.close();
				} catch (IOException e) {
					logger.warn("Error Closing Response Stream",e);
				}
			}
			return StringEscapeUtils.unescapeHtml(stringOut.toString());
		}
		return null;
	}

The newer Apache HttpComponents Project offers some evolutionary features over HttpClient like Plug-able authentication mechanisms, but the code shown above based on the legacy HttpClient libs works very well for my needs and is easily upgradeable should the need arise.

Technology