You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 13 Next »

Rest DSL

Available as of Camel 2.14

Apache Camel offers a REST styled DSL which can be used with Java or XML. The intention is to allow end users to define REST services using a REST style with verbs such as get, post, delete etc.

How it works

The Rest DSL is a facade that builds Rest endpoints as consumers for Camel routes. The actual REST transport is leveraged by using Camel REST components such as RestletSpark-rest, and others that has native REST integration.

Components supporting Rest DSL

The following Camel components supports the Rest DSL. See the bottom of this page for how to integrate a component with the Rest DSL.

Rest DSL with Java

To use the Rest DSL in Java then just do as with regular Camel routes by extending the RouteBuilder and define the routes in the configure method.

A simple REST service can be define as follows, where we use rest() to define the services as shown below:

    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                rest("/say/hello")
                    .get().to("direct:hello");
                rest("/say/bye")
                    .get().consumes("application/json").to("direct:bye")
                    .post().to("mock:update");

                from("direct:hello")
                    .transform().constant("Hello World");
                from("direct:bye")
                    .transform().constant("Bye World");
            }
        };
    }

 

This defines a REST service with the following url mappings:

Uri templateVerbConsumes
/say/hellogetall
/say/byegetapplication/json
/say/byepostall

Notice that in the REST service we route directly to a Camel endpoint using the to(). This is because the Rest DSL has a short-hand for routing directly to an endpoint using to(). An alternative is to embed a Camel route directly using route() - there is such an example further below.

Rest DSL with XML

The REST DSL supports the XML DSL also using either Spring or Blueprint. The example above can be define in XML as shown below:

  <camelContext xmlns="http://camel.apache.org/schema/spring">
    <rest uri="/say/hello">
      <get>
        <to uri="direct:hello"/>
      </get>
    </rest>
    <rest uri="/say/bye">
      <get consumes="application/json">
        <to uri="direct:bye"/>
      </get>
      <post>
        <to uri="mock:update"/>
      </post>
    </rest>
    <route>
      <from uri="direct:hello"/>
      <transform>
        <constant>Hello World</constant>
      </transform>
    </route>
    <route>
      <from uri="direct:bye"/>
      <transform>
        <constant>Bye World</constant>
      </transform>
    </route>
  </camelContext>

 

Using path prefixes

The REST DSL allows to define path prefixes to make the DSL a bit more DRY. For example to define a customer path, we can set the prefix in rest("/customer") and then provide the past postfix in the verbs, as shown below:

  rest("/customers/")
      .get("/{id}").to("direct:customerDetail")
      .get("/{id}/orders").to("direct:customerOrders")
      .post("/neworder").to("direct:customerNewOrder");

 

And using XML DSL it becomes:

    <rest uri="/customers/">
      <get uri="/{id}">
        <to uri="direct:customerDetail"/>
      </get>
      <get uri="/{id}/orders">
        <to uri="direct:customerOrders"/>
      </get>
      <post uri="/neworder">
        <to uri="direct:customerNewOrder"/>
      </post>
    </rest>

The REST DSL will take care of duplicate path separators when using path prefixes. In the example above the rest path prefix ends with a slash ( / ) and the verb starts with a slash ( / ). But Apache Camel will take care of this and remove the duplicated slash.

Embedding Camel routes

Each of the rest service becomes a Camel route, so in the first example we have 2 x get and 1 x post REST service, which each become a Camel route. And we have 2 regular Camel routes, meaning we have 3 + 2 = 5 routes in total. 

There are two route modes with the Rest DSL

  • mini using a singular to
  • embedding a Camel route using route 

The first example is using the former with a singular to. And that is why we end up with 3 + 2 = 5 total routes.

The same example could use embedded Camel routes, which is shown below:

    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                rest("/say/hello")
                    .get().route().transform().constant("Hello World");
                rest("/say/bye")
                    .get().consumes("application/json").route().transform().constant("Bye World").endRest()
                    .post().to("mock:update");
        };
    }

In the example above, we are embedding routes directly in the rest service using .route(). Notice we need to use .endRest() to tell Camel where the route ends, so we can go back to the Rest DSL and continue defining REST services.

Configuring route options

In the embedded route you can configure the route settings such as routeId, autoStartup and various other options you can set on routes today.

.get().route().routeId("myRestRoute").autoStartup(false).transform().constant("Hello World");

 Managing Rest services

Each of the rest service becomes a Camel route, so in the first example we have 2 x get and 1 x post REST service, which each become a Camel route. This makes it the same from Camel to manage and run these services - as they are just Camel routes. This means any tooling and API today that deals with Camel routes, also work with the REST services.

This means you can use JMX to stop/start routes, and also get the JMX metrics about the routes, such as number of message processed, and their performance statistics.

Binding to POJOs using

The Rest DSL supports automatic binding json/xml contents to/from POJOs using Camels Data Format. By default the binding mode is off, meaning there is no automatic binding happening for incoming and outgoing messages.

You may want to use binding if you develop POJOs that maps to your REST services request and response types. This allows you as a developer to work with the POJOs in Java code.

The binding modes are:

Binding ModeDescription
offBinding is turned off. This is the default option.
autoBinding is enabled and Camel is relaxed and support json, xml or both if the needed data formats are included in the classpath. Notice that if for example camel-jaxb is not on the classpath, then XML binding is not enabled.
jsonBinding to/from json is enabled, and requires a json capabile data format on the classpath. By default Camel will use json-jackson as the data format.
xmlBinding to/from xml is enabled, and requires camel-jaxb on the classpath.
json_xmlBiding to/from json and xml is enabled and requires both data formats to be on the classpath.

 

To use binding you must include the necessary data formats on the classpath, such as camel-jaxb and/or camel-jackson. And then enable the binding mode. You can configure the binding mode globally on the rest configuration, and then override per rest service as well.

To enable binding you configure this in Java DSL as shown below

restConfiguration().component("restlet").host("localhost").port(portNum).bindingMode(RestBindingMode.auto);

And in XML DSL

    <restConfiguration bindingMode="auto" component="restlet" port="8080"/>

 

When binding is enabled Camel will bind the incoming and outgoing messages automatic, accordingly to the content type of the message. If the message is json, then json binding happens; and so if the message is xml then xml binding happens. The binding happens for incoming and reply messages. The table below summaries what binding occurs for incoming and reply messages. 

Message BodyDirectionBinding ModeMessage Body
XMLIncoming

auto
xml
json_xml 

POJO
POJOOutgoingauto
xml
json_xml 
XML
JSONIncomingauto
json
json_xml 
POJO
POJOOutgoingauto
json
json_xml 
JSON

 

When using binding you must also configure what POJO type to map to. This is mandatory for incoming messages, and optional for outgoing. 

For example to map from xml/json to a pojo class UserPojo you do this in Java DSL as shown below:

// configure to use restlet on localhost with the given port
// and enable auto binding mode
restConfiguration().component("restlet").host("localhost").port(portNum).bindingMode(RestBindingMode.auto);

// use the rest DSL to define the rest services
rest("/users/")
    .post("new").type(UserPojo.class)
        .to("direct:newUser");

Notice we use type to define the incoming type. We can optionally define an outgoing type (which can be a good idea, to make it known from the DSL and also for tooling and JMX APIs to know both the incoming and outgoing types of the REST services.). To define the outgoing type, we use outType as shown below:

// configure to use restlet on localhost with the given port
// and enable auto binding mode
restConfiguration().component("restlet").host("localhost").port(portNum).bindingMode(RestBindingMode.auto);

// use the rest DSL to define the rest services
rest("/users/")
    .post("new").type(UserPojo.class).outType(CountryPojo.class)
        .to("direct:newUser");


The UserPojo is just a plain pojo with getter/setter as shown:

public class UserPojo {
    private int id;
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

The UserPojo only supports json, as XML requires to use JAXB annotations, so we can add those annotations if we want to support XML also

@XmlRootElement(name = "user")
@XmlAccessorType(XmlAccessType.FIELD)
public class UserPojo {
    @XmlAttribute
    private int id;
    @XmlAttribute
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

By having the JAXB annotations the POJO supports both json and xml bindings.

 

Configuring Rest DSL

The Rest DSL allows to configure the following options using a builder style

 

OptionDefaultDescription
component The Camel Rest component to use for the REST transport, such as restlet, spark-rest. If no component has been explicit configured, then Camel will lookup if there is a Camel component that integrates with the Rest DSL, or if a org.apache.camel.spi.RestConsumerFactory is registered in the registry. If either one is found, then that is being used.
schemehttpThe scheme to use for exposing the REST service. Usually http or https is supported
hostname0.0.0.0The hostname to use for exposing the REST service.
port The port number to use for exposing the REST service.
bindingModeoffWhether binding is in use. See further above for more details.
jsonDataFormat Name of specific json data format to use. By default json-jackson will be used. Notice: Currently Jackson is what we recommend and are using for testing.
xmlDataFormat Name of specific XML data format to use. By default jaxb will be used. Notice: Currently only jaxb is supported.
componentProperty Allows to configure as many additional properties. This is used to configure component specific options such as for Restlet / Spark-Rest etc.
endpointProperty Allows to configure as many additional properties. This is used to configure endpoint specific options for  Restlet / Spark-Rest etc.
consumerProperty Allows to configure as many additional properties. This is used to configure consumer specific options for  Restlet / Spark-Rest etc.
dataFormatProperty Allows to configure as many additional properties. This is used to configure the data format specific options. For example set property prettyPrint to true to have json outputted in pretty mode.

 

For example to configure to use the spark-rest component on port 9091, then we can do as follows

restConfiguration().component("spark-rest").port(9091).componentProperty("foo", "123");


And with XML DSL

<restConfiguration component="spark-rest" port="9091"> <componentProperty key="foo" value="123"/> </restConfiguration>


You can configure properties on three levels. 

  • component - Is used to set any options on the Component class. You can also configure these directly on the component.
  • endpoint - Is used set any option on the endpoint level. Many of the Camel components has many options you can set on endpoint level.
  • consumer - Is used to set any option on the consumer level. Some components has consumer options, which you can also configure from endpoint level by prefixing the option with "consumer." 

You can set multiple options of the same level, so you can can for example configure 2 component options, and 3 endpoint options etc.

Integration a Camel component with Rest DSL

Any Apache Camel component can integrate with the Rest DSL if they can be used as a REST service (eg as a REST consumer in Camel lingo). To integrate with the Rest DSL, then the component should implement the org.apache.camel.spi.RestConsumerFactory. The Rest DSL will then invoke the createConsumer method when it setup the Camel routes from the defined DSL. The component should then implement logic to create a Camel consumer that exposes the REST services based on the given parameters, such as path, verb, and other options. For example see the source code for camel-restlet, camel-spark-rest.

 

See Also

DSL

Rest

Spark-rest

  • No labels