Simplify Integrations With OpenFeign in AEM
Sometimes when I meet someone, the question comes up "What do you do for a living." I answer "I'm an internet plumber!" I create the connections that connect back-end systems and people to the data they need.
So last year when a pipe burst in my home, the plumber ran over to the hardware store. Bought some new pipes. And resolved the issue. Thats right! They ran over to the hardware store and bought some new pipes! They didn't go back to their workshop to smelt copper. Pour it into a cast. Then cut and clean to get a finished pipe.
So why would I, an internet plumber, spend time and effort writing the same foundational code. Project after project, year after year. I'm talking about back-end RESTful integrations in AEM.
Part of the problem is that AEM only ships with 2 HTTP clients. I talked about them in my last post. So when tasked with an integration, developers will blast away with one of those. This is the gap that OpenFeign fills. It is modular and extensible. And it lets you define an HTTP client using annotations & configurations. This is what OSGi R7 Declarative Services did for OSGi component development.
Importing OpenFeign Into AEM
Importing bundles into AEM is always a tricky proposition. As a reference point, I am using the following
This version of AEM ships with the following bundles
Under the hood, these are the libraries OpenFeign will use. And I have opted to import OpenFeign 11.9. The reason for this was simple. The AEMaaCS Local Build Analyzers complained. An api-regions-exportsimports error to be exact.
In plain words this means that the OpenFeign bundle has a dependency on Jackson 12.4. And the AEM SDK can not provide that. Instead of fighting it, I chose to acquiesce. After all the analyzer's job is to prevent me from shooting my self in the foot. Why fight it?
Crack open your all/pom.xml and add the following dependencies.
And embed them in the content package
Once installed, they will get activated and listed in the Felix console
feign-core is the main bundle. While feign-jackson and feign-jaxb provide the decoders and encoders. You may only need one. I am importing both because in my examples I will show how easy it is to switch from JSON to XML.
Start with a Unit Test
In my last post I set up WireMock to test my code. For this I am using WireMock as well. But to keep things brief, I will do a more advanced post on WireMock some other time.
For now, this is my unit test. I am testing an OSGi component named CustomerService. And it has a single method named getCustomer.
This service will fetch a customer record from some back-end system via JSON REST API. And that service requires a subscription key. To get passed on each request in a header named Ocp-Apim-Subscription-Key. So right away you may start to make a list of the things you need to do to write this service.
Create An Interface and Annotate
The first thing we will do is create an interface. And annotate it with the OpenFeign annotations. Even though I don't have to, I am throwing in a custom exception. To show the how modular OpenFeign is. The REST API at http://example.com/customer/<customer_guid> will respond with a JSON object. And that will get serialized to a Customer DTO. If anything goes wrong, the response will get packed into a custom exception. This is optional. The FeignException class already implements a good set of common exceptions.
Write The Service
Finally, lets write the service. In which I will write zero code to create a request. Or deserialize the response.
I build an instance of the CustomerAPI interface. I set the decoder to JacksonDecoder because the responses will be in JSON. I set the error encoder to my custom exception. And oh yeah, I set a request interceptor that will add that subscription key to every request.
Then the getCustomer method will use the client to get the customer. And if anything fails, it handles the exception by tossing back a null.
Adding An Encoder and Switching the Content-Type
So now we want to add a method to create a customer. That means a PUT request. With some sort of JSON body. But lets say we want to switch to XML. Now I add this to the CustomerAPI interface
And the CustomerService will call it
And here is the key part. We update the client build
The API supports content negotiation. So I send the Accept header to instruct it to respond in XML. I switch to the JAXBDecoder so I can decode responses. And I add the JAXBEncoder. Because the client will need to serialize the Customer DTO into the PUT request. And that is all that changed. The unit test didn't change. And I didn't have to spend time switching all the JSON serialization to XML.
Spending several hours tracing through code to find out someone forgot to set a header is no fun! Using OpenFeign simplifies things and makes the code maintainable. Its modular architecture is flexible. And it allows you to focus on your application instead of the low level details. Like how the requests get made and processed.