/alchemy-http

Talk easily to REST Services in Java

Primary LanguageKotlinApache License 2.0Apache-2.0

Alchemy HTTP

"REST without the MESS"

Build Status Maven Central Version

Purpose

Part of the Alchemy Collection.

Why can't making a REST call in Java be as easy and fluid as it is for other languages?

Making REST calls in other languages is FAR SIMPLER!

Javascript

In JavaScript:

$.ajax({
	   url: "http://aroma.tech/placeOrder",
	   type: 'POST',
	   data: { "size": "large",
	   		"type": "black",
	   		"amount": 3
		}
   }).then(function(data) {
	  var orderNumber = data.orderNumber;
   });

Ruby

In Ruby:

uri = URI('http://aroma.tech/orders?orderNumber=99')
Net::HTTP.get(uri) # => String

Java

Meanwhile, back in Java land...

HttpClient apacheHttp = //Good luck figuring out how to create me

//Create the JSON Object, line by line...
JsonObject orderRequest = new JsonObject();
orderRequest.put("size", "large");
orderRequest.put("type", "black");
orderRequest.put("amount", 3);

//Set up the request method
HttpPost post = new HttpPost("http://aroma.tech/orders");

//Stick the body in the body
Entity body = new StringEntity(orderRequest.toString(), "application/json");
post.setEntity(body);

//Execute the actual request
HttpResponse apacheResponse;
try
{
	apacheResponse = apacheHttp.execute(post);
}
catch(Exception ex)
{
	LOG.error("Oh god!", ex);
	throw new OperationFailedException(ex);
}

//Check the Response Code
if(apacheResponse.getStatusLine().getStatusCode() != 200)
{
	LOG.error("The Service didn't like our response");
	throw new OperationFailedException();
}

//Read the entity response
Entity responseEntity = apacheResponse.getEntity();
String responseString = null;
try (final InputStream istream = responseEntity.getContent())
{
	//If you're lucky enough to have Guava
 	byte[] rawBytes = ByteStreams.toByteArray(istream);
	responseString = new String(rawBytes, Charsets.UTF_8);
}
 catch (IOException ex)
{
	LOG.error("Failed to read entity from request", ex);
  	throw new RuntimeException(ex);
}

//Then you gotta parse the string
//Good luck with that one...

All that just to get some damn JSON data!

Come on Java! No wonder they hate us. We can do better than that.

The Alchemy Way

AlchemyHttp http = AlchemyHttp.Factory.newDefaultInstance();

Coffee myCoffee = http.go()
                      .get()
		      .expecting(Coffee.class)
		      .at("http://aroma.tech/orders?orderNumber=99");
//Wait...that's it?

That's it!

The Async Way

There may be times when you don't care to wait for an immediate response from the service. An Async response would actually make a lot more sense.

Just show me the damn code!

http.go()
    .post()
    .body(request)
    .expecting(Coffee.class)
    .onSuccess(c -> LOG.warn("What took you so long to get my cofee! {}", c))
    .onFailure(ex -> LOG.error("What can I do without coffee?", ex))
    .at("http://aroma.tech/orders");

Another way

To be fair Java Lambdas aren't as clean as Blocks in other languages. It's often better to things somewhere else. Try using a method reference instead, for example:

class BaristaService
{
	private AlchemyHttp http;

	@Override
	public void serveCustomer(Customer customer)
	{
		http.go()
		    .get()
		    .expecting(Coffee.class)
		    .onSuccess(coffee -> customer.accept(coffee))
		    .onFailure(this::handleOrderIssue)
		    .at("http://aroma.tech/orders");
	}

	private void handleOrderIssue(AlchemyException ex)
	{
		HttpResponse response = ex.getResponse();
		LOG.error("What happened to our Coffee Machine? {} | {}" , response, response.statusCode());
		Map<String,String> responseHeaders = response.responseHeaders();
	}
}

Download

To use, simply add the following maven dependency.

Release

<dependency>
	<groupId>tech.sirwellington.alchemy</groupId>
	<artifactId>alchemy-http</artifactId>
    <version>3.4.1</version>
</dependency>

Tested Against

This library has been tested against in-house as well as production services. This is not a comprehensive list, but should give you some idea of compatibility.

Slack

https://api.slack.com

Gitter

https://developer.gitter.im/docs/welcome

Google APIs

Geocoding

https://maps.googleapis.com/maps/api/geocode/json

Documentation found here

Places API

https://maps.googleapis.com/maps/api/place/nearbysearch/json

Documentation found here

Mashape APIs

Mashape has many great test APIs found here.

More on the way...

Requirements

  • Java 8
  • Maven installation

Building

To build, just run a mvn clean install to compile and install to your local maven repository

Feature Requests

Feature Requests are definitely welcomed! Please drop a note in Issues.

Release Notes

3.0

  • Client re-written in Kotlin
  • Dropped usage of Apache HTTP Client, in favor of plain-java's URLConnection API
  • Full compatibility for Android

2.0

  • Significantly reduces footprint, making this library suitable for the Android platform.
  • Bugfixes and Improvements

1.3

  • Bugfixes and Improvements
  • Dependency Updates

1.2

  • Bugfixes and Improvements
  • Dependency Updates

1.1

  • Bugfixes and Improvements
  • Dependency Updates

1.0

  • Initial Public Release

License

This Software is licensed under the Apache 2.0 License

http://www.apache.org/licenses/LICENSE-2.0