Mule Tutorial Series: Implementing RESTful WebService

An ESB is expected to function as a service provider as well as a consumer. This tutorial will explain how Mule ESB can be configured to function as a RESTful WebService endpoint. Mule ESB provides a built-in REST component based on Jersey project.

In the first example, we will explore the possibility of creating RESTful web services without using the built-in component; in the next example we will create a RESTful web service with Jersey.

The mule flow for this example is depicted below.

RESTful WebService without Jersey Component
RESTful WebService without Jersey Component

The HTTP endpoint of the flow is configured as below. The examples of the earlier post covered one way HTTP end point, this one covers two way or request-response paradigm.

The following configuration settings are done in the ‘General’ tab of the HTTP component.

Exchange-patterns: request-response
Host: localhost
Port: 8086
Path: rest

The next component in the flow is Body to Parameter Body. Retain the default values. The final component in the flow is Maps to XML component. Retain the default values for this component as well.

To invoke the application, open any browser window and type the following:

http://localhost:8086/rest?name=Harry&age=40

The output generated in the browser window is shown below:

<?xml version="1.0" encoding="UTF-8"?>
<table>
	<record>
		<field name="age" type="java.lang.String">40</field>
		<field name="name" type="java.lang.String">Harry</field>
	</record>
</table>

The output XML structure rendered is the default format of the Maps to XML transformer component. It is not possible to customize this output.

The source code of the mule flow is shown below:

<mule>
    <flow name="http_restfulwsFlow1" doc:name="http_restfulwsFlow1">
        <http:inbound-endpoint exchange-pattern="request-response" 
			host="localhost" port="8086" path="rest" 
			mimeType="text/plain" contentType="text/plain" 
			doc:name="HTTP"/>
        <response>
            <jdbc-ee:maps-to-xml-transformer doc:name="Maps to XML"/>
        </response>
        <http:body-to-parameter-map-transformer doc:name="Body to Parameter Map"/>
    </flow>
</mule>

For all practical purposes, the developer would like to have the ability to customize the output XML into a more sensible format aligned to business domain. To achieve the same a new Mule flow is created.

RESTful WebService Using Custom Object to XML converter
RESTful WebService Using Custom Object to XML convertor

The HTTP end point is configured as below.

Exchange-patterns:request-response
Host: localhost
Port: 8087
Path:rest

Body to Parameter map component needs no explanation. The Maps to XML component has been replaced by a new component namely Object to XML.

The configuration of the Object to XML component is below. Use the ‘Advanced’ tab.

Aliases – Name: Persons
Aliases – Class Name: java.util.Map
Converters – Class Name: com.vinraj.integration.rest.PersonConverter

The Object to XML component uses XStream, an open source XML data binding framework to achieve XML marshalling and unmarshalling.

When a POJO is provided to XStream to create an XML, the fully qualified class name is used as the enclosing XML element name. In case the developer wants to override this he/she provides a key-value pair specifying the class name and its custom alias. Here we have replaced the Map with the alias ‘Persons’. The converter class converts POJO internal structure into its equivalent custom XML structure. The source code of PersonConverter is shown below:

package com.vinraj.integration.rest;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class PersonConverter implements Converter {

	@Override
	public boolean canConvert(Class arg0) {
		if (Map.class.equals(arg0) || HashMap.class.equals(arg0)) {
			return Boolean.TRUE;
		} else {
			return Boolean.FALSE;
		}
	}

	@Override
	public void marshal(Object object, HierarchicalStreamWriter writer,
			MarshallingContext ctx) {
		Map map = (Map)object;
		Set names = map.keySet();
		writer.startNode("Person");
		for (Object name : names) {
			writer.startNode(name.toString());
			String value = (String)map.get(name);
			writer.setValue(value);
			writer.endNode();
		}
		writer.endNode();

	}

	@Override
	public Object unmarshal(HierarchicalStreamReader arg0,
			UnmarshallingContext arg1) {
		return null;
	}
}

The canConvert method specifies the POJO classes which can use this converter. The marshal method is responsible for the custom conversion of the input Map data structure. The unmarshal method is unimplemented as the reverse conversion of XML to object is not required.

To test the application, run the following URL in the browser window:

http://localhost:8087/rest?name=Harry&age=40

The output generated in the browser window is shown below:

<Persons>
  <Person>
    <age>40</age>
    <name>Harry</name>
  </Person>
</Persons>

The source code of this flow is shown below

<?xml version="1.0" encoding="UTF-8"?>

<mule>
    <flow name="http_restfulCustomXMLFlow1" doc:name="http_restfulCustomXMLFlow1">
        <http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8087" path="rest" doc:name="HTTP"/>
        <response>
            <mulexml:object-to-xml-transformer doc:name="Object to XML">
            	<mulexml:alias name="Persons" class="java.util.Map"/>
                <mulexml:converter class="com.vinraj.integration.rest.PersonConverter"/>
            </mulexml:object-to-xml-transformer>
        </response>
        <http:body-to-parameter-map-transformer doc:name="Body to Parameter Map"/>
    </flow>
</mule>

Note: the XML namespaces added within the mule element tag has been removed for code legibility.

The previous two examples covered how to develop a RESTful web service API in Mule without using its built-in REST component. This example demonstrates the use of the Mule REST component.

The Mule flow for RESTful Web Service API is shown below:

RESTful WebService with Jersey component
RESTful WebService with Jersey component

The HTTP end point is configured as below.

Exchange-patterns:request-response
Host: localhost
Port: 8092
Path:jersey

In the REST component in the ‘General’ tab specify the following configuration:

Class: com.vinraj.integration.rest.RestImpl
The source code of the RestImpl class is shown below:

@Path("/schools")
public class RestImpl {

	@GET
	@Produces(MediaType.APPLICATION_XML)
	@Path("/{id}")
	public Response getSchoolDetails(@PathParam("id")String param) {
		System.out.println("Retrieving School details"); 
		StringBuilder sb = new StringBuilder();
		sb.append("<Schools>\n");
		if ("1".equals(param)) {
			sb.append("<School>\n");
			createIdTag(param, sb);
			createNameTag("Father Agnel's school", sb);
			createRatingTag("3.5", sb);
			sb.append("</School>\n");
		} else if ("2".equals(param)) {
			sb.append("<School>\n");
			createIdTag(param, sb);
			createNameTag("Gurukul school", sb);
			createRatingTag("3.0", sb);
			sb.append("</School>\n");			
		} else {
			sb.append("<Error>");
			sb.append("School not found!");
			sb.append("</Error>\n");
			sb.append("</Schools>\n");
			return Response.ok(sb.toString()).build();
		}
		sb.append("</Schools>\n");
		return Response.ok(sb.toString()).build();
	}
	@GET
	@Produces(MediaType.APPLICATION_XML)
	@Path("/{id}/children")
	public Response getChildrenDetails(@PathParam("id")String id, @QueryParam("childid")String childId) {
		System.out.println("Retrieving Children details"); 
		StringBuilder sb = new StringBuilder();
		sb.append("<Schools>\n");
		if ("1".equals(id)) {
			sb.append("<School>\n");
			createIdTag(id, sb);
			createNameTag("Father Agnel's school", sb);
			createRatingTag("3.5", sb);
			addChildren(childId, sb);
			sb.append("</School>\n");
		} else if ("2".equals(id)) {
			sb.append("<School>\n");
			createIdTag(id, sb);
			createNameTag("Gurukul school", sb);
			createRatingTag("3.0", sb);
			addChildren(childId, sb);
			sb.append("</School>\n");			
		} else {
			sb.append("<Error>");
			sb.append("School not found!");
			sb.append("</Error>\n");
			sb.append("</Schools>\n");
			return Response.ok(sb.toString()).build();
		}
		sb.append("</Schools>\n");
		return Response.ok(sb.toString()).build();
	}

private void createIdTag(String param, StringBuilder sb) {
		sb.append("<Id>");
		sb.append(param);
		sb.append("</Id>\n");
	}

	private void createNameTag(String param, StringBuilder sb) {
		sb.append("<Name>");
		sb.append(param);
		sb.append("</Name>\n");
	}

	private void createRatingTag(String param, StringBuilder sb) {
		sb.append("<Rating>");
		sb.append(param);
		sb.append("</Rating>\n");
	}

	private void addChildren(String childId, StringBuilder sb) {
		sb.append("<Children>\n");
		if ("1".equals(childId)) {
			createNameTag("Star1", sb);
		} else if ("2".equals(childId)) {
			createNameTag("Star2", sb);
		} else {
			
			if(childId != null) {
				sb.append("<Error>");
				sb.append("No children associated with this school");
				sb.append("</Error>\n");
			} else {
				createNameTag("Star1", sb);
				createNameTag("Star2", sb);
				createNameTag("Star3", sb);
			}
		}
		sb.append("</Children>\n");
	}
}

The two methods of RestImpl to understand are getSchoolDetails and getChildrenDetails; the other methods are purely supportive to these two methods.

In a typical RESTful web service implementation, the individual API needs to map to URL. The Path annotation with value “/schools” defines the root URL for this class. The individual method level extensions to the root URL are defined using the Path annotation at method level. For the getSchoolDetails method the relative URL path is /schools/, where the user is supposed to submit a valid id value. For getChildrenDetails method the relative URL path is schools//children. Additionally the getChildrenDetails also supports query parameter childid, hence the relative URL is /schools//children?childid=.

The rest of the code of the method is self-explanatory. A String containing the response XML is passed to the Response object’s ok method to signify a normal HTTP status code 200 response.

One last thing, I have referred to the URLs as relative as they are relative to the path defined in the HTTP end point. The complete URL will include /jersey as a prefix to the relative URLs mentioned above.

The source code of mule flow is shown below

<mule>
    <flow name="rest_exampleFlow1" doc:name="rest_exampleFlow1">
        <http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8092" path="jersey" 
        	  method="GET" doc:name="HTTP"/>
        <jersey:resources doc:name="REST">
            <component class="com.vinraj.integration.rest.RestImpl"/>
        </jersey:resources>
    </flow>
</mule>

To test the Mule application, run the following URLs in the browser window:

http://localhost:8092/jersey/schools/1
http://localhost:8092/jersey/schools/2/children
http://localhost:8092/jersey/schools/112
http://localhost:8092/jersey/schools/1/children?childid=3

The output generated in the browser window for

http://localhost:8092/jersey/schools/1

is shown below:

<Schools>
	<School>
		<Id>1</Id>
		<Name>Father Agnel's school</Name>
		<Rating>3.5</Rating>
	</School>
</Schools>

The output generated in the browser window for

http://localhost:8092/jersey/schools/2/children

is shown below:

<Schools>
	<School>
		<Id>2</Id>
		<Name>Gurukul school</Name>
		<Rating>3.0</Rating>
		<Children>
			<Name>Star1</Name>
			<Name>Star2</Name>
			<Name>Star3</Name>
		</Children>
	</School>
</Schools>

The output generated in the browser window for

http://localhost:8092/jersey/schools/112

is shown below:

<Schools>
	<Error>School not found!</Error>
</Schools>

The output generated in the browser window for

http://localhost:8092/jersey/schools/1/children?childid=3

is shown below:

<Schools>
	<School>
		<Id>1</Id>
		<Name>Father Agnel's school</Name>
		<Rating>3.5</Rating>
		<Children>
			<Error>No children associated with this school</Error>
		</Children>
	</School>
</Schools>

That’s all for now.

Advertisements

8 thoughts on “Mule Tutorial Series: Implementing RESTful WebService

  1. Excellent tutorials – very easy to understand with all the details of the config parameters you provide.
    I hope you will continue to provide more such tutorials

  2. Can you please tell me how to send the post request using REST component in Mule, the examples which you have shared all are GET request. Please share POST request example too.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s