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:
- Introduction
- Application configuration
- Get operation
- Put and post operations
- Delete operation
- 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.
Labels: Integration, REST, Spring, web services