REST DSL
Apache Camel offers a REST styled DSL.
The intention is to allow end users to define REST services (hosted by Camel) using a REST style with verbs such as get, post, delete, etc.
| From Camel 4.6 onwards, the Rest DSL has been improved with a contract-first approach using vanilla OpenAPI specification files. This is documented in the Rest DSL with OpenAPI contract first page. This current page documents the code-first Rest DSL that Camel provides for a long time. |
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 Netty HTTP, Servlet, and others that have native REST integration.
Components supporting Rest DSL
The following Camel components support the Rest DSL:
-
camel-rest required contains the base rest component needed by Rest DSL
-
camel-platform-http (recommended)
Rest DSL
Lets defines a REST service with the following url mappings:
| Base Path | Uri template | Verb | Consumes |
|---|---|---|---|
|
|
| all |
|
|
|
|
|
|
| all |
-
Java
-
XML
-
YAML
To use the Rest DSL in Java DSL, 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 defined as follows, where we use rest() to define the services as shown below:
@Override
public void configure() throws Exception {
rest("/say")
.get("/hello").to("direct:hello")
.get("/bye").consumes("application/json").to("direct:bye")
.post("/bye").to("mock:update");
from("direct:hello")
.transform().constant("Hello World");
from("direct:bye")
.transform().constant("Bye World");
} Notice that in the REST service we route directly to a Camel endpoint using to(). This is because the Rest DSL has a shorthand for routing directly to an endpoint using to().
A simple REST service can be defined as follows, where we use <rest> to define the services as shown below:
<rest path="/say">
<get path="/hello">
<to uri="direct:hello"/>
</get>
<get path="/bye" consumes="application/json">
<to uri="direct:bye"/>
</get>
<post path="/bye">
<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> A simple REST service can be defined as follows, where we use - rest: to define the services as shown below:
- rest:
path: "/say"
get:
- path: "/hello"
to: "direct:hello"
- path: "/bye"
consumes: "application/json"
to: "direct:bye"
post:
- path: "/bye"
to: "direct:update"
- route:
from:
uri: direct:hello
steps:
- transform:
expression:
constant:
expression: Hello World
- route:
from:
uri: direct:bye
steps:
- transform:
expression:
constant:
expression: Bye World Using a base path
The REST DSL allows defining a base path to help applying the "don’t repeat yourself" (DRY) practice. For example, to define a customer path, we can set the base path in rest("/customer") and then provide the uri templates in the verbs, as shown below:
-
Java
-
XML
-
YAML
rest("/customers/")
.get("/{id}").to("direct:customerDetail")
.get("/{id}/orders").to("direct:customerOrders")
.post("/neworder").to("direct:customerNewOrder"); <rest path="/customers/">
<get path="/{id}">
<to uri="direct:customerDetail"/>
</get>
<get path="/{id}/orders">
<to uri="direct:customerOrders"/>
</get>
<post path="/neworder">
<to uri="direct:customerNewOrder"/>
</post>
</rest> - rest:
path: "/customers/"
get:
- path: "/{id}}"
to: "direct:customerDetails"
- path: "/{id}/orders}"
to: "direct:customerOrders"
post:
- path: "/neworder"
to: "direct:customerNewOrder" The REST DSL will take care of duplicate path separators when using base path and uri templates. In the example above the rest base path ends with a slash / and the verb starts with a slash /. Camel will take care of this and remove the duplicated slash. |
It is not required to use both base path and uri templates. You can omit the base path and define the base path and uri template in the verbs only. The example above can be defined as:
-
Java
-
XML
-
YAML
rest()
.get("/customers/{id}").to("direct:customerDetail")
.get("/customers/{id}/orders").to("direct:customerOrders")
.post("/customers/neworder").to("direct:customerNewOrder"); <rest>
<get path="/customers/{id}">
<to uri="direct:customerDetail"/>
</get>
<get path="/customers/{id}/orders">
<to uri="direct:customerOrders"/>
</get>
<post path="/customers/neworder">
<to uri="direct:customerNewOrder"/>
</post>
</rest> - rest:
get:
- path: "/customers/{id}}"
to: "direct:customerDetails"
- path: "/customers/{id}/orders}"
to: "direct:customerOrders"
post:
- path: "/customers/neworder"
to: "direct:customerNewOrder" You can combine path parameters to build complex expressions.
For example the following defines a path for a getting an item as if it was a file syntax:
-
Java
-
XML
-
YAML
rest("items/")
.get("{id}/{filename}.{content-type}")
.to("direct:item"); <rest path="items/">
<get path="{id}/{filename}.{content-type}">
<to uri="direct:item"/>
</get>
</rest> - rest:
path: "items/"
get:
- path: "{id}/{filename}.{content-type}"
to: "direct:item" Managing Rest services
Each of the rest services becomes a Camel route, so in the first example, we have 2 x get and 1 x post REST service, which each becomes a Camel route.
This makes it the same from Apache 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.
To use JMX with Camel then camel-management JAR must be included in the classpath. |
This means you can use JMX to stop/start routes, and also get the JMX metrics about the routes, such as the number of messages processed, and their performance statistics.
There is also a Rest Registry JMX MBean that contains a registry of all REST services that has been defined.
Inline Rest DSL as a single route
| Camel 4.4 or older has inline-routes disabled by default. Camel 4.5 or newer has inline-routes enabled by default. |
Each of the rest services becomes a Camel route, and this means, that if the rest service is calling another Camel route via direct, which is a widespread practice. This means that each rest service then becomes two routes. This can become harder to manage if you have many rest services.
When you use direct endpoints then you can enable Rest DSL to automatically inline the direct route in the rest route, meaning that there is only one route per rest service.
When using inline-routes, then each REST endpoint should link 1:1 to a unique direct endpoint. The linked direct routes are inlined and therefore does not exists as independent routes, and they cannot be called from other regular Camel routes. In other words the inlined routes are essentially moved inside the rest-dsl and does not exist as a route. See more detils further below. |
To do this you MUST use direct endpoints, and each endpoint must be unique name per service. And the option inlineRoutes must be enabled.
For example, in the Java DSL below we have enabled inline routes and each rest service uses direct endpoints with unique names.
-
Java
-
XML
-
YAML
restConfiguration().inlineRoutes(true);
rest("/customers/")
.get("/{id}").to("direct:customerDetail")
.get("/{id}/orders").to("direct:customerOrders")
.post("/neworder").to("direct:customerNewOrder"); <restConfiguration inlineRoutes="true"/>
<rest>
<get path="/customers/{id}">
<to uri="direct:customerDetail"/>
</get>
<get path="/customers/{id}/orders">
<to uri="direct:customerOrders"/>
</get>
<post path="/customers/neworder">
<to uri="direct:customerNewOrder"/>
</post>
</rest> - restConfiguration:
inlineRoutes: true
- rest:
get:
- path: "/customers/{id}}"
to: "direct:customerDetails"
- path: "/customers/{id}/orders}"
to: "direct:customerOrders"
post:
- path: "/customers/neworder"
to: "direct:customerNewOrder" If you use Camel Main, Camel Spring Boot, Camel Quarkus or Camel CLI, you can also enable this in application.properties such as:
camel.rest.inline-routes = true Notice the REST services above each use a unique 1:1 linked direct endpoint (direct:customerDetail, direct:customerOrders direct:customerNewOrder). This means that you cannot call these routes from another route such as the following would not function:
-
Java
-
XML
-
YAML
from("kafka:new-order")
.to("direct:customerNewOrder"); <route>
<from uri="kafka:new-order"/>
<to uri="direct:customerNewOrder"/>
</route> - route:
from:
uri: kafka:new-order
steps:
- to:
uri: direct:customerNewOrder So if you desire to call common routes from both Rest DSL and other regular Camel routes then keep these in separate routes as shown:
-
Java
-
XML
-
YAML
restConfiguration().inlineRoutes(true);
rest("/customers/")
.get("/{id}").to("direct:customerDetail")
.get("/{id}/orders").to("direct:customerOrders")
.post("/neworder").to("direct:customerNewOrder");
from("direct:customerNewOrder")
// do some stuff here
.to("direct:commonCustomerNewOrder"); // call common route
from("direct:commonCustomerNewOrder")
// do stuff here
.log("Created new order");
from("kafka:new-order")
.to("direct:commonCustomerNewOrder"); // make sure to call the common route <restConfiguration inlineRoutes="true"/>
<rest path="/customers/">
<get path="/{id}">
<to uri="direct:customerDetail"/>
</get>
<get path="/{id}/orders">
<to uri="direct:customerOrders"/>
</get>
<post path="/neworder">
<to uri="direct:customerNewOrder"/>
</post>
</rest>
<routes>
<route>
<from uri="direct:customerNewOrder"/>
<to uri="direct:commonCustomerNewOrder"/>
</route>
<route>
<from uri="direct:commonCustomerNewOrder"/>
<log message="Created new order"/>
</route>
<route>
<from uri="kafka:new-order"/>
<to uri="direct:commonCustomerNewOrder"/>
</route>
</routes> - restConfiguration:
inlineRoutes: true
- rest:
path: "/customers/"
get:
- path: "/{id}}"
to: "direct:customerDetails"
- path: "/{id}/orders}"
to: "direct:customerOrders"
post:
- path: "/neworder"
to: "direct:customerNewOrder"
- route:
from:
uri: direct:customerNewOrder
steps:
- to:
uri: direct:commonCustomerNewOrder
- route:
from:
uri: direct:commonCustomerNewOrder
steps:
- log:
message: Created new order
- route:
from:
uri: kafka:new-order
steps:
- to:
uri: direct:commonCustomerNewOrder Notice how the common shared route is separated into the route direct:commonCustomerNewOrder. Which can be called from both Rest DSL and regular Camel routes.
Disabling REST services
While developing REST services using Rest DSL, you may want to temporary disabled some REST endpoints, which you can do using disabled as shown in the following.
-
Java
-
XML
-
YAML
rest("/customers/")
.get("/{id}").to("direct:customerDetail")
.get("/{id}/orders").to("direct:customerOrders").disabled("{{ordersEnabled}}")
.post("/neworder").to("direct:customerNewOrder").disabled(); <rest>
<get path="/customers/{id}">
<to uri="direct:customerDetail"/>
</get>
<get path="/customers/{id}/orders" disabled="{{ordersEnabled}}">
<to uri="direct:customerOrders"/>
</get>
<post path="/customers/neworder" disabled="true">
<to uri="direct:customerNewOrder"/>
</post>
</rest> - rest:
get:
- path: "/customers/{id}}"
to: "direct:customerDetails"
- path: "/customers/{id}/orders}"
to: "direct:customerOrders"
disabled: "{{ordersEnabled}}"
post:
- path: "/customers/neworder"
to: "direct:customerNewOrder"
disabled: "true" In this example the last two REST endpoints are configured with disabled. You can use Property Placeholder to let an external configuration determine if the REST endpoint is disabled or not. In this example the /customers/{id}/orders endpoint is disabled via a placeholder. The last REST endpoint is hardcoded to be disabled.
More Information
For detailed documentation on specific topics, see the following sub-pages:
-
Binding and Configuration — POJO binding, Jackson JSON features, CORS, OAuth Bearer token validation
-
Error Handling and Validation — Custom error messages, request/response validation, parameter defaults
-
Contract First with OpenAPI — Using vanilla OpenAPI specification files with Rest DSL