Monday, December 22, 2014

Exposing HTTP Restful API with Inbound Adapters. Part 2 (Java DSL)

1   Introduction


In the previous part of this tutorial, we implemented an application exposing a Restful API using XML configuration. This part will re-implement this application using Spring Integration Java DSL.

The application is implemented with Java 8, but when Java 8 specific code is used (for example, when using lambdas), I will also show you how to do it in Java 7. Anyway, I shared both versions at Github in case you want to check it out:

Java 7 Java DSL example

Java 8 Java DSL example


This post is divided into the following sections
  1. Introduction
  2. Application configuration
  3. Get operation
  4. Put and post operations
  5. Delete operation
  6. Conclusion


2   Application configuration


In the web.xml file, the dispatcher servlet is configured to use Java Config:

In the pom.xml file, we include the Spring Integration Java DSL dependency:

InfrastructureConfiguration.java

The configuration class contains bean and flow definitions.

In order to parse payload expressions, we define a bean parser, using an SpELExpressionParser.

The header mapper will later be registered as a property of inbound gateways, in order to map HTTP headers from/to message headers.

The detail of the flows and endpoints defined in this configuration class is explained in each of the following sections.


3   Get operation


Our first step is to define the HTTP inbound gateway that will handle GET requests.

The createMapping method is the Java alternative to the request-mapping XML element seen in the previous part of the tutorial. In this case, we can also use it to define the request path and supported methods.

Now that we have our gateway set, let’s define the flow that will serve GET requests (remember you can check a diagram of the full flow in the previous part of the tutorial):

The flow works as follows:
  • from(httpGetGate()): Get messages received by the HTTP Inbound Gateway.
  • channel(“httpGetChannel”): Register a new DirectChannel bean and send the message received to it.
  • handle(“personEndpoint”, “get”): Messages sent to the previous channel will be consumed by our personEndpoint bean, invoking its get method.

Since we are using a gateway, the response of the personEndpoint will be sent back to the client.

I am showing the personEndpoint for convenience, since it’s actually the same as in the XML application:

GetOperationsTest uses a RestTemplate to test the exposed HTTP GET integration flow:

I won’t show the full class since it is the same as in the XML example.


4   Put and post operations


Continuing with our Restful API application example, we define a bean for the HTTP inbound channel adapter.  You may notice that we are creating a new Gateway. The reason is that inbound channel adapter is internally implemented as a gateway that is not expecting a reply.

We are again using the parser to resolve the returned status code expression.

The former XML attribute request-payload-type of the inbound adapter is now set as a property of the gateway.

The flow that handles both PUT and POST operations uses a router to send the message to the appropriate endpoint, depending on the HTTP method received:

The flow is executed the following way:
  • from(httpPostPutGate()):Get messages received by the HTTP Inbound adapter.
  • channel(“routeRequest”): Register a DirectChannel bean and send the message received to it.
  • route(...): Messages sent to the previous channel will be handled by a router, which will redirect them based on the HTTP method received (http_requestMethod header). The destination channel is resolved applying the prefix and suffix. For example, if the HTTP method is PUT, the resolved channel will be httpPutChannel, which is a bean also defined in this configuration class.

Subflows (httpPutFlow and httpPostFlow) will receive messages from the router and handle them in our personEndpoint.

Since we defined an inbound adapter, no response from the endpoint is expected.

In the router definition we used Java 8 lambdas. I told you I would show the alternative in Java 7, so a promise is a promise:

A little bit longer, isn’t it?

The PUT flow is tested by the PutOperationsTest class:

The POST flow is tested by the PostOperationsTest class:


5   Delete operation


With this operation we complete our application. The entry point is defined by the following bean:

The configuration is pretty similar to the PutPost gateway. I won’t explain it again.

The delete flow sends the deletion request to the personEndpoint:

And our bean will request the service to delete the resource:

The test asserts that the resource no longer exists after deletion:


6   Conclusion


This second part of the tutorial has shown us how to implement a Spring Integration application with no XML configuration, using the new Spring Integration Java DSL. Although flow configuration is more readable using Java 8 lambdas, we still have the option to use Java DSL with previous versions of the language.

I'm publishing my new posts on Google plus and Twitter. Follow me if you want to be updated with new content.




Exposing HTTP Restful API with Inbound Adapters. Part 1 (XML)

1   Introduction


The purpose of this post is to implement an HTTP Restful API using Spring Integration HTTP inbound adapters. This tutorial is divided into two parts:

  • XML configuration example (this same post).
  • Java DSL example. This will be explained in the next part of this tutorial, showing how to configure the application using Spring Integration Java DSL, with examples with both Java 7 and Java 8.

Before looking at the code, let’s take a glance at the following diagram, which shows the different services exposed by the application:


GET operations are handled by an HTTP inbound gateway, while the rest (PUT, POST and DELETE) are handled by HTTP inbound channel adapters, since no response body is sent back to the client. Each operation will be explained in the following sections:
  1. Introduction
  2. Application configuration
  3. Get operation
  4. Put and post operations
  5. Delete operation
  6. Conclusion
The source code is available at Github.


2   Application configuration


The web.xml file contains the definition of the Dispatcher Servlet:

The http-inbound-config.xml file will be explained in the following sections.

The pom.xml file is detailed below. It is important to note the jackson libraries. Since we will be using JSON to represent our resources, these libraries must be present in the class path. Otherwise, the framework won’t register the required converter.


3   Get operation


The configuration of the flow is shown below:

http-inbound-config.xml

The gateway receives requests to this path: /persons/{personId}. Once a request has arrived, a message is created and sent to httpGetChannel channel. The gateway will then wait for a service activator (personEndpoint) to return a response:

Now, some points need to be explained:

  • supported-methods: this attribute indicates which methods are supported by the gateway (only GET requests).
  • payload-expression: What we are doing here is getting the value from personId variable in the URI template and putting it in the message’s payload. For example, the request path ‘/persons/3’ will become a Message with a value ‘3’ as its payload.
  • request-mapping: We can include this element to specify several attributes and filter which requests will be mapped to the gateway. In the example, only requests that contain the value ‘application/json’ for Content-Type header (consumes attribute) and Accept header (produces attribute) will be handled by this gateway.

Once a request is mapped to this gateway, a message is built and sent to the service activator. In the example, we defined a simple bean that will get the required information from a service:

Depending on the response received from the service, we will return the requested person or a status code indicating that no person was found.

Now we will test that everything works as expected. First, we define a ClientPerson class to which the response will be converted:

Then we implement the test. The buildHeaders method is where we specify Accept and Content-Type headers. Remember that we restricted requests with ‘application/json’ values in those headers.

Not specifying a correct value in the Content-Type header will result in a 415 Unsupported Media Type error, since the gateway does not support this media type.

On the other hand, specifying an incorrect value in the Accept header will result in a 406 Not Acceptable error, since the gateway is returning another type of content than the expected.


4   Put and post operations


For PUT and POST operations, we are using the same HTTP inbound channel adapter, taking advantage of the possibility to define several paths and methods to it. Once a request arrives, a router will be responsible to delivering the message to the correct endpoint.

http-inbound-config.xml

This channel adapter includes two new attributes:

  • status-code-expression: By default, the channel adapter acknowledges that the request has been received and returns a 200 status code. If we want to override this behavior, we can specify a different status code in this attribute. Here, we specify that these operations will return a 204 No Content status code.
  • request-payload-type: This attribute specifies what class will the request body be converted to. If we do not define it, it will not be able to convert to the class that the service activator is expecting (ServerPerson).


When a request is received, the adapter sends it to the routeRequest channel, where a router is expecting it. This router will inspect the message headers and depending on the value of the ‘http_requestMethod’ header, it will deliver it to the appropriate endpoint.

Both PUT and POST operations are handled by the same bean:

Return type is void because no response is expected; the inbound adapter will handle the return of the status code.

PutOperationsTest validates that the correct status code is returned and that the resource has been updated:

PostOperationsTest validates that the new resource has been added:


5   Delete operation


The last operation of our restful API is the delete operation. This time we use a single channel adapter for this purpose:

The channel adapter lets us define the returning status code and we are using the payload-expression attribute to map the requested personId to the message body. The configuration is a little bit different from  those in previous operations but there’s nothing not already explained here.

The service activator, our person endpoint, will request the person service to delete this resource.

Finally, the required test:


6   Conclusion


This post has been an introduction to our application in order to understand how it is structured from a known point of view (xml configuration). In the next part of this tutorial, we are going to implement this same application using Java DSL. The application will be configured to run with Java 8, but when lambdas are used, I will also show how it can be done with Java 7.

You can read the second part of this tutorial here.

I'm publishing my new posts on Google plus and Twitter. Follow me if you want to be updated with new content.