Calling a REST service from Apache Camel
I spend a lot of time integrating with other services in my day job. Most of the time, this means talking to REST APIs.
If you’re like me, you’ve probably wondered: “How do I call these REST services from Camel?” Which component should I use? What’s the easiest way to do it?
In this article, I’ll share my preferred approach to calling external web services from Camel, along with some real code you can use. And yes, I’ll be using a cat-related example because, well, I like cats! 🐈
Let’s dive in!
What do we need from our Camel kit bag?
Figuring out how to implement something in Apache Camel can be a bit overwhelming when you’re a beginner. Where do you even begin?
We want to invoke a REST API. So let’s take a look at what we need to do, step-by-step:
-
First, we need something to trigger the REST request. In Camel, we’re always responding to a trigger, event or request. A Camel route always starts with a component which acts as the trigger.
So… I’ll use a Timer component to start the route, which will fire the route immediately. But you could start your route with something else, like a Direct component or a JMS component.
-
We need to build up a URL dynamically. We might need to modify some parts of the REST API URL, depending on values that we know about. For example, the URL of the REST API might change, depending on the username of the requester, or the Product ID that you’re trying to retrieve.
So… I’ll use the ToD EIP in Camel, which is one way to send a message to an endpoint, if the URL needs to be dynamic. It’s useful if the URL can only be known at runtime. You can also use the Recipient List pattern for this.
-
We need to make an HTTP request. Calling a REST service is basically just making a simple HTTP request, and there are lots of different ways to do this in Camel. We just need to use a component which can be used as an HTTP client.
So… I’ll use Camel’s HTTP component (previously called the “HTTP4” component). It’s a simple HTTP client, that we can use to make GET requests, POST requests, or anything we want.
Invoking a REST service from Camel, step-by-step
Let’s do it! Let’s invoke a REST service using Apache Camel.
To follow the steps in this tutorial with your own service, you need to have Apache Camel already set up in your project.
Don’t have a Camel project yet? If you don’t have Camel added into your project, go to the Spring Initializr to create a new Spring Boot app with Camel support, or create a new Camel project from a Maven archetype.
This code has been verified with Apache Camel 3.0.0.
-
Let’s add our Maven dependencies. In the section above, I said we’re going to use the HTTP component. It’s a simple HTTP client, which is perfect for us.
To use it, you need to add the
camel-http
dependency to your Maven POM:<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-http</artifactId> </dependency>
Using a version of Camel prior to 3.0? You’ll need to use the dependency
camel-http4
. The component was renamed in Camel 3 and the number 4 was dropped. -
Let’s add a new Camel route to our RouteBuilder class. This route will call the external web service.
I’m going to start the route with a Timer, just to make it easy to run.
from("timer:mytimer?repeatCount=1") //....the rest of the route will go here.
Notice how I’m setting the repeat counter to 1, so that it only executes once.
Depending on your app, you might want to start this route with a Direct component instead, or perhaps a JMS component if you’re reading from a queue.
-
Set the body of the request. We do this using the
setBody
step. The contents of the Body will be used when making the HTTP request.I’m going to send some arbitrary JSON, just some information about a cat: 🐈
.setBody(simple("{ \"cat\": \"Milo\" }"))
If you’re making a
GET
request to your REST API, you shouldn’t need this step. So you can set the body to null if you prefer:.setBody(simple("${null}"))
-
Set anything else dynamic you might need in the request. In this example, I’m calling a Cat API (yes I like cats) and it will expect a cat name in the URL.
I’m using constant to set a constant value – but you might use something dynamic here to set the value you need:
.setHeader("catName", constant("Bernice"))
-
Using Camel’s toD pattern to create a dynamic URI, we build the target URL which we want to invoke. The URL begins with
http
, which will use the HTTP component we added above.Here I also show you how you could include something dynamic in the URL. Dynamic values in Camel that are part of the message being processed will usually be stored in a header, or in the body. Earlier, I stored a value in a header,
catName
, so I’m using${header.catName}
to reference it:.toD("http://www.examplecat.com/cats/${header.catName}" + "?httpMethod=POST")
We add
httpMethod
, to tell the HTTP component which HTTP action (verb) we want to use. If you need to useGET
,PUT
, or something else, you should update this property. -
Now do something with the response from the RESTful service. Once we’ve made the request, we can access the response in the Camel Exchange Body, e.g.:
.log("The body was - ${body}");
Adding authentication (optional)
If you need to provide a username and password to the REST request, you can use the auth
parameters, like this:
.toD("http://www.examplecat.com/cats/${header.catName}" +
"?httpMethod=GET" +
"&authMethod=Basic" +
"&authUsername=" +
"&authPassword=" +
"&authenticationPreemptive=true")
This will send credentials to the service, using Basic HTTP authentication.
The complete example and sample code
Let’s put it all together.
The following example Camel route calls a RESTful service. It uses the GitHub API to create a new private Gist in your account.
from("direct:create-gist")
.log("Creating a Gist on GitHub...")
// Set the body to null, because it is required by the GitHub API.
// But you can set the body here to anything you like.
// This is the content of our Gist.
// See: https://docs.github.com/en/rest/reference/gists#create-a-gist
.transform(simple("{\"files\":{\"README.md\":{\"content\":\"Hello from Camel!\"}}}"))
// Now invoke the GitHub API with the Gist JSON in the body
// POST /gists
.to("https://api.github.com/gists" +
"?httpMethod=POST" +
"&authMethod=Basic" +
"&authUsername=" +
"&authPassword=" +
"&authenticationPreemptive=true")
.log("Response code from the Create Gist operation was: ${header.CamelHttpResponseCode}")
.log("Response body from the Create Gist operation was: ${body}");
If you want to run this demo, set up a Personal Access Token in your GitHub account and then grab the source code from GitHub. See the link below:
See the example code on GitHub