Sunday, October 20, 2013

Exposing RESTful interface with Mule pt.2

In previous part of this article I've presented two ways of building REST API on Mule ESB: using Mule REST Module and handling HTTP properties manually.

This time I want to present achieving the same result using Mule Jersey Module with addition of
Component Bindings - feature of Mule, which enables us to leave Java and go back to Mule flow processing.

Presented example was tested against Mule ESB 3.4.0 EE.

3. Jersey REST

Flow overview:

Unfortunately, not much to see in this graphical overview - devil is in the details :)

Jersey REST Component is the official recommendation for exposing REST Services on Mule ESB. Usually, this reference implementation of JAX-RS would be everything we need to achieve the goal. However, in terms of Mule, it ties us heavily to Java code, which is not what we are especially looking for. To overcome this we can use Component Bindings.

Let's go back to our example. Staring with the simple Jersey service class:
@Path(value = "/")
public class JerseyRestService {

 private FlowProcessing flowProcessing;

 @GET
 @Path(value = "/client/{accountID}/{userID}/get")
 public Response processGET(@PathParam("accountID") String accountId, @PathParam("userID") String userId) {
  String result = flowProcessing.processGET(accountId, userId);
  return Response.ok(result).build();
 }

 @POST
 @Path(value = "/client/{accountID}/{userID}/get")
 public Response processPOST(@PathParam("accountID") String accountId, @PathParam("userID") String userId, String body) {
  String result = flowProcessing.processPOST(accountId, userId, body);
  return Response.ok(result).build();
 }

 public void setFlowProcessing(FlowProcessing flowProcessing) {
  this.flowProcessing = flowProcessing;
 }
}

Nothing fancy here. JAX-RS plain and simple. Interesting part is the FlowProcessing interface. It looks like it's wrapping whole business logic processing. By using Component Bindings we can make any Mule's outbound endpoint behave as an implementation of that interface. Hence, we can make use of VM endpoints and move the processing from Java back to Mule flows:
<jersey:resources doc:name="REST">
  <component class="pl.poznachowski.jerseyrest.JerseyRestService">
    <binding interface="pl.poznachowski.jerseyrest.FlowProcessing" method="processGET">
      <vm:outbound-endpoint exchange-pattern="request-response" path="vmProcessGET" />
    </binding>
    <binding interface="pl.poznachowski.jerseyrest.FlowProcessing" method="processPOST">
      <vm:outbound-endpoint exchange-pattern="request-response" path="vmProcessPOST" />
    </binding>
  </component>
  <jersey:exception-mapper class="pl.poznachowski.jerseyrest.BadURIExceptionMapper" />
</jersey:resources>

As seen above, everything we need to make it work is to provide binding element specifying the interface, interface's method and outbound endpoint, which should be called. Few things to remember:

  • Don't forget to write setter for the interface in the Jersey class. 
  • Make sure that request and response of the interface and endpoint matches 
  • It is possible to have the method return MuleMessage. It lets Java component have access to whole message, not only payload.

Flows with the "business logic" for POST and GET methods processing are described below:
<flow name="ProcessGetFlow" doc:name="ProcessGetFlow">
  <vm:inbound-endpoint exchange-pattern="request-response" path="vmProcessGET" doc:name="VM" />
  <transformer ref="populateVariables" doc:name="Populate variables"/>
  <set-payload value="Processing GET with account id: #[accountID] and user id: #[userID]" doc:name="Set Payload" />
</flow>
<flow name="ProcessPostFlow" doc:name="ProcessPostFlow">
  <vm:inbound-endpoint exchange-pattern="request-response" path="vmProcessPOST" doc:name="VM" />
  <transformer ref="populateVariables" doc:name="Populate variables"/>
  <set-payload value="Processing POST with account id: #[accountID] and user id: #[userID] and body: #[payload]"
doc:name="Set Payload" />
</flow>
Input parameters of the FlowProcessing interface methods comes in the Mule flows as an Object array. We can map them into Mule parameters by writting and setting global transformer:
<custom-transformer class="pl.poznachowski.jerseyrest.PopulateVariables" name="populateVariables" doc:name="Java" />
and reusing it in the flows (<transformer ref="populateVariables" />).

PopulateVariables Java transformer:
public class PopulateVariables extends AbstractMessageTransformer {

 @Override
 public MuleMessage transformMessage(MuleMessage message, String outputEncoding) throws TransformerException {

  Object[] args = message.getPayload(Object[].class);
  message.setInvocationProperty("accountID", args[0]);
  message.setInvocationProperty("userID", args[1]);

  // For POST method
  if (args.length > 2) {
   message.setPayload(args[2]);
  }

  return message;
 }
}

We have everything in place to make it work. One thing I don't like is that Jersey for requests with URL not met is returning 404 HTTP status (Not Found). I find 400 status (Bad Request) more appropriate in such case and I'd like to keep 404 reserved for situations where URL was met, but resource was not found. Satysfying that requirement is fairly simple. We need to add a custom exception mapper in Jersey definition:
<jersey:exception-mapper class="pl.poznachowski.jerseyrest.BadURIExceptionMapper" />
with implementation:
public class BadURIExceptionMapper implements ExceptionMapper<NotFoundException> {

  public Response toResponse(NotFoundException exception){
      return Response.status(Response.Status.BAD_REQUEST).entity("Unknown resource: " + exception.getNotFoundUri().toString()).build();
  }
}

Note: It is possible to catch exceptions thrown in the binded outbound endpoints. To make that possible we just need to declare exception in binding interface method.

To test described solution I used the same set of tests as in previous post. However I was having problems testing successful scenarios using MUnit:
ERROR 2013-10-17 22:30:02,434 [main] org.mule.exception.DefaultMessagingExceptionStrategy:
********************************************************************************
Message               : Failed to invoke JerseyResourcesComponent$$EnhancerByCGLIB$$8a425d6{JerseyRestFlow.component.206873183}. Component that caused exception is: JerseyResourcesComponent$$EnhancerByCGLIB$$8a425d6{JerseyRestFlow.component.206873183}. Message payload is of type: String
Code                  : MULE_ERROR--2
--------------------------------------------------------------------------------
Exception stack is:
1. The required object/property "muleContext" is null (java.lang.IllegalArgumentException)
  org.mule.DefaultMuleMessage:292 (null)
2. Failed to invoke JerseyResourcesComponent$$EnhancerByCGLIB$$8a425d6{JerseyRestFlow.component.206873183}. Component that caused exception is: JerseyResourcesComponent$$EnhancerByCGLIB$$8a425d6{JerseyRestFlow.component.206873183}. Message payload is of type: String (org.mule.component.ComponentException)
  org.mule.component.AbstractComponent:148 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/component/ComponentException.html)

It seems that muleContext is not propagated correctly with MUnit and reflective proxy classes. Switching test class to use 'official' FunctionalTestCase instead of MUnit worked like a charm.

Full example at GitHub: JerseyREST

That were all the solutions for exposing REST Services I can think of.
In my work project, I'm using the REST Module and it's doing its job well. Thus, if you want build REST API and use all of the nifty Mule features  I would suggest going with the Router Module.
If you prefer to be more Java-centric, make use of Mule for handling integration matter only or to use Mule flows to a smaller extent then Jersey approach will fit in.

For more information about Component Bindings I encourage you to read Mule's well-written blog post explaining the feature.

Friday, October 11, 2013

Exposing RESTful interface with Mule pt.1

Update (20.10.2013) - When not supported HTTP method is used, return more appropriate HTTP status (405 instead of 400).

As it's my first blog entry I'd like to welcome everyone. If you'd like to know more about me click on the tab above. If not.. I'll go straight to the point.

Recently, I had to create Mule's application, which exposes itself via a simple RESTful API. However, when it comes to REST, Mule ESB seems to be quite limited in viable options.
The only, official approach is to use the REST Component, which relies on Jersey, which is the Reference Implementation of JAX-RS. Sounds good, but it ties you to the Java code instead of having fun with the Mule's message processing :) This can be overcome as well, but still some Java needs to be written.

Fortunately, there are some other possibilites, which would make simple REST API creation easier. Nevertheless, I'd like to present you all the options (of which I'm aware of) with description and a working example.

All presented examples were tested against Mule ESB 3.4.0 EE. However, they should run without any problems on CE and even on previous versions.

1. "Poor man's" REST:

First approach is the most straightforward one - handling HTTP properties available in Mule manually. Quick overview over HTTP properties is available here - (1.4.7 Use Case) in archived Mule Developer Resources.

In that case, we need to take care of detecting the HTTP method, URL and fetching URL variable parameters by ourselves. We can accomplish that using Mule's choice component and setting flow variables (if needed).
An example will accept URL (on 8088 port) as follows: /client/{accountID}/{userID}/get on both GET and POST HTTP methods, where {accountID} and {userID} are the variable parameters.

General overview of the flow:


First step is not necessary, but helpful for quick suppresion of favicon.ico requests when accesing service via browsers:
<message-filter doc:name="Filter favicon">
  <not-filter>
    <wildcard-filter casesensitive="true" pattern="/favicon.ico">
  </wildcard-filter></not-filter>
</message-filter>
To match URL let's use choice component with regular expression:
<choice doc:name="Choice">
  <when expression="#[regex('/client/\\w+/\\w+/get/?', message.inboundProperties['http.request.path'])]">
   ...
 </when>
  <otherwise>
    <http:response-builder status="400" doc:name="Return 400 For bad URL">
      <set-payload value="Unknown resource: #[message.inboundProperties['http.request.path']]" />
    </http:response-builder>
  </otherwise>
</choice>
We retrieve URL path using Mule's inbound property - 'http.request.path', then match it with the regexp '/client/\\w+/\\w+/get/?'. If we don't have a match we just simply return 400 HTTP status.
Otherwise, we can proceed and determine which HTTP method was used to send the request:
<choice doc:name="Choice">
  <when expression="message.inboundProperties['http.method'] == 'GET'">
    <flow-ref name="RetrievingParameters" doc:name="Retrieve Parameters"/>
    <flow-ref name="ProcessGET" doc:name="Process GET"/>
  </when>
  <when expression="message.inboundProperties['http.method'] == 'POST'">
    <flow-ref name="RetrievingParameters" doc:name="Retrieve Parameters"/>
    <flow-ref name="ProcessPOST" doc:name="Process POST"/>
  </when>
  <otherwise>
    <http:response-builder status="405" doc:name="Return 405 For bad HTTP method">
      <set-payload value="Unknown HTTP method: #[message.inboundProperties['http.method']]" />
    </http:response-builder>
  </otherwise>
</choice>
This time we are checking another inbound parameter - 'http.method'. If it's not the method we want to proceed with, we return 405 HTTP status (Method Not Allowed).

For all supported methods we want to fetch the URL parameters. Hence, this functionality is extracted to a reusable sub-flow:
<sub-flow name="RetrievingParameters" doc:name="RetrievingParameters">
  <set-variable variableName="accountID" value="#[StringUtils.splitAndTrim(message.inboundProperties['http.request.path'], '/')[1]]" doc:name="Set Account ID"/>
  <set-variable variableName="userID" value="#[StringUtils.splitAndTrim(message.inboundProperties['http.request.path'], '/')[2]]" doc:name="Set User ID"/>
</sub-flow>
As I'm not good at regular expressions, I decided to go with Mule's StringUtils method, which splits the URL and gets me the parameters I'm looking for.

To avoid providing fully qualified name of the class over and over again, we can define global import for Mule expressions:
<configuration doc:name="Configuration">
  <expression-language>
    <import class="org.mule.util.StringUtils" />
  </expression-language>
</configuration>
That is basically everything we needed. We can now process GET / POST requests. For readability and maintainability reasons we will do that in separate flows:
<flow name="ProcessPOST" doc:name="ProcessPOST">
  <http:response-builder status="200"doc:name="Return OK">
    <set-payload value="Processing POST with account id: #[accountID] and user id: #[userID] and body: #[payload]" doc:name="Set Payload"/>
  </http:response-builder>
</flow>
<flow name="ProcessGET" doc:name="ProcessGET">
  <http:response-builder status="200"doc:name="Return OK">
    <set-payload value="Processing GET with account id: #[accountID] and user id: #[userID]" doc:name="Set Payload"/>
  </http:response-builder>
</flow>
 
To test my service I've prepared a test class with couple of Mule functional tests. Instead of using default FunctionalTestCases, I suggest using MUnit. From what I know, it is supposed to replace current Mule testing solution in future. With MUnit you can write your tests using Java (JUnit) or XML (Mule code). It has features like mocking endpoints, processors and ability to call flow directly, skipping inbound endpoints. However, development of MUnit seemed to slow down recently.
To keep the test concise, I used JUnitParams extension, as I wanted to use same test methods, but with different input (URLs).

Additionally, we could've checked for content-type etc., but I didn't want to clutter the code with insignificant details.
Having in mind next example, I'm not exactly sure, if anyone would opt for this approach. But still, there it is, probably for demonstration purposes only ;)

Full example at GitHub: PoorMansREST

2. REST Router

To make our lives easier Mule REST Router Module has been developed. Code is available at GitHub.
Almost everything we did in previous approach is wrapped into one message processor. Installation and configuration is well explained in the links provided.

Flow overview:

Basically, to implement same behaviour, we need to configure rest-router as follows:
<rest-router:router templateUri="/client/{accountID}/{userID}/get">
  <rest-router:get>
    <flow-ref name="ProcessGET" doc:name="Process GET" />
  </rest-router:get>
  <rest-router:post>
    <flow-ref name="ProcessPOST" doc:name="Process POST" />
  </rest-router:post>
</rest-router:router>

REST Router automatically assign parameters specified in templateUri to flow variables. However, I found out that it passes through empty parameters, so it is advisable to validate them explicitly in your code.
Outstanding part is to cover invalid URLs and return something meaningful. For requests not matching our template we return standard 400 HTTP status (placed just after </rest-router:router>) :

<http:response-builder status="400" doc:name="Return 400 For bad URL">
  <set-payload value="Unknown resource: #[message.inboundProperties['http.request.path']]" />
</http:response-builder>

For HTTP methods not supported REST Router should (per documentation) throw UnsupportedHttpVerbException. However, there is an issue I submitted here. Unfortunately, the project looks abandoned as nobody cared :) I did some more research and it appears that the issue is not in the REST Router itself, but how the DevKit java code is generated.
There are two solutions for that:
1) Always implement whole set of methods in REST Router and return appriopriate message / status / throw exception in those you don't want to support.
2) As I don't like to have redundancy in my code I used a dirty hack of replacing compiled class with a fixed one directly in the jar file. Amended version of the module is available here. Just install it in your local Maven repository and switch module version in your pom.xml file to 1.2-fixed.

Fix description:
HTTP method recognition is implemented as in the following snippet: (RestRouterModule.java)
if (get != null && method.equalsIgnoreCase("get")) {
 return get.processWithExtraProperties(properties);
} else if (put != null && method.equalsIgnoreCase("put")) {
 return put.processWithExtraProperties(properties);
} else if (post != null && method.equalsIgnoreCase("post")) {
 return post.processWithExtraProperties(properties);
} else if (delete != null && method.equalsIgnoreCase("delete")) {
 return delete.processWithExtraProperties(properties);
} else if (patch != null && method.equalsIgnoreCase("patch")) {
 return patch.processWithExtraProperties(properties);
} else {
 throw new UnsupportedHttpVerbException(method);
}
Variables: get, put, post... are instances of NestedProcessor class, marked @Optional.
However, code generated by DevKit always propagates those variables to the RestRouterModule as instances of NestedProcessorChain (RouterMessageProcessor.java):
final NestedProcessor _transformedGet = new NestedProcessorChain(event, getMuleContext(), ((MessageProcessor) get));
final NestedProcessor _transformedPut = new NestedProcessorChain(event, getMuleContext(), ((MessageProcessor) put));
final NestedProcessor _transformedPost = new NestedProcessorChain(event, getMuleContext(), ((MessageProcessor) post));
final NestedProcessor _transformedDelete = new NestedProcessorChain(event, getMuleContext(), ((MessageProcessor) delete));
final NestedProcessor _transformedPatch = new NestedProcessorChain(event, getMuleContext(), ((MessageProcessor) patch));
Those _transformed method variables are passed into the RestRouterModule class, hence it always tries to process the processWithExtraProperties(properties) method and eventually finishes with NullPointerException as the last argument in NestedProcessorChain contructor is null.

My fixed version of RouterMessageProcessor.java includes following change:
final NestedProcessor _transformedGet = (get == null) ? null : new NestedProcessorChain(event, getMuleContext(), ((MessageProcessor) get));
final NestedProcessor _transformedPut = (put == null) ? null : new NestedProcessorChain(event, getMuleContext(), ((MessageProcessor) put));
final NestedProcessor _transformedPost = (post == null) ? null : new NestedProcessorChain(event, getMuleContext(), ((MessageProcessor) post));
final NestedProcessor _transformedDelete = (delete == null) ? null : new NestedProcessorChain(event, getMuleContext(), ((MessageProcessor) delete));
final NestedProcessor _transformedPatch = (patch == null) ? null : new NestedProcessorChain(event, getMuleContext(), ((MessageProcessor) patch));
Not much to explain here. Now, if a REST module HTTP method is not defined it will propagate null to RestRouterModule.java and throw UnsupportedHttpVerbException as expected.

In the flow we use standard choice exception strategy and catch the UnsupportedHttpVerbException to return 405 HTTP status:

  
    
      
    
  


For testing I used the same set of tests as in previous example. As you can see, it's much quicker and cleaner approach that saves you a lot of time and lines of code :)

Full example (using modified version of the module) at GitHub: RestWithRouter

In the next part I will present how to achieve the same, but using Jersey with writing as little Java as possible. Go here for the second part!