Testing Java HTTP Clients in AEM
Updated: May 7
As part of my job, I review a lot of code. One of the problems that I see often is that a lot of code gets written to integrate AEM with RESTful services. It is always very complex because it has to deal with different content types. Authentication headers. And methods. And this complexity is hard to test and debug.
HTTP Clients in AEM
When I began working on AEM, it was on the last version of CQ5. Running on Java 1.8. And back then (if memory serves) there were 2 HTTP clients available. The native HttpURLConnection. And Apache HTTP Components 3.
Depending on how old your project is, you may still find it uses HttpURLConnection. This is the native client for 1.8.
For modern projects, I do not recommend you use it. I am only putting here as an example.
This is a small GET example. It gets much worse. This client is the oldest client in the Java world. It offers a clunky API. And lacks modern features like asynchronous requests.
Apache HTTP Components 3.x
Apache HTTP Components filled the gaps left by HTTPUrlConnection. It is a well designed API. With a lot of configuration options.
Version 3.1 ships with AEM for backward compatibility. And I am putting this sample code here for reference. You may have run across this client if you are migrating to newer versions of AEM. On AEMaaCS, the Cloud Manager will flag these deprecated APIs.
If you are curious, here is the set of examples released with 3.x.
Apache HTTP Components 4.x
Currently AEM ships with version 4.5.x of the client. If you are working on a modern AEM project, this is the client to use.
Java 11 HTTP Client
Even if you are working on a modern AEM project, you may still be using Java 1.8. In which case you get limited to Apache Http Components 4.5.x. But if you are on Java 11, you can use its native HTTP client.
You can find a lot of comparisons between it, and the Apache version. They both follow a builder pattern. They can do synchronous and asynchronous. They do more or less the same. Or at least I have not run into any issues. If I had to choose... I would choose the Java 11 client. Only because I don't need to worry about closing connections.
Here is the same example as before.
What we have learned so far is that there are 2 HTTP clients available to you in a modern AEM project. It does not matter which one you choose. You will run into a problem when you write a unit test. How do you mock these clients?
In the past I used static mocking to mock the builders. But that leads to a lot of mocking code. And it is not interchangeable between clients. I have found the easiest approach is mock servers. Such as WireMock.
This is an example of basic mocking with WireMock. I am testing the Java 11 client. I don't care too much about the implementation. Only that my service is able to query the endpoint and return the response.
In this second example, I am using the advanced approach. Where I have more control over the configuration. In this case, I am adding an extension for response templating. And I am testing the Apache Client 4.5.x implementation. But it can get swapped for the Java 11.
And here is the templated body file. It should be under the __files root directory of the test resources. src/test/java/resources/__files/dataService.json.
In this post I covered the Java HTTP clients available in AEM. They get used to integrate AEM with RESTful services. I only demonstrated simple GET requests. Things become more complex when dealing with authentication, other content types and methods.
Using WireMock makes testing the complex code simpler. But it does not actually simplify the code. In my next post I will tackle the complexity problem. By using OpenFeign. And get rid of the need for WireMock altogether.