Build REST/GraphQL APIs with Apache Camel
Apache Camel is a powerful integration framework that simplifies the connection of systems and the exposure of APIs. Let us delve into understanding how Apache Camel facilitates integration with GraphQL and REST APIs.
1. Introduction to Apache Camel and GraphQL
Apache Camel is a lightweight, open-source integration framework that helps developers implement complex Enterprise Integration Patterns (EIPs). Designed to simplify integration tasks, Camel enables routing, mediation, transformation, and protocol bridging between heterogeneous systems. It comes with a vast library of components that support a wide range of transport and messaging protocols, including REST, HTTP, JMS, Kafka, File, FTP, and many others.
Camel leverages a domain-specific language (DSL) that allows integration logic to be expressed in Java, XML, Kotlin, or YAML. Its routing engine enables developers to define flows declaratively, which significantly reduces boilerplate code. One of its key features is the ability to decouple business logic from transport logic, making services easier to manage and evolve over time.
GraphQL, developed by Facebook, is an advanced query language and runtime for APIs that enables precise and efficient data fetching. Instead of multiple endpoints like in REST, GraphQL operates through a single endpoint and relies on a type system defined in a schema. Clients specify the shape and fields of the data they need, and the server responds with exactly that data—nothing more, nothing less.
This reduces over-fetching and under-fetching of data, especially in mobile and low-bandwidth environments. GraphQL also supports powerful features such as real-time subscriptions, introspection, and deeply nested queries. Its flexibility and client-centric design make it a popular alternative to REST for modern applications.
Combining Apache Camel with GraphQL allows developers to build powerful, decoupled systems where data aggregation, transformation, and routing can be managed within Camel routes, while data querying and schema-driven access are handled by GraphQL. This integration brings the best of both worlds—robust backend orchestration with a highly customizable client interface.
2. Setting up the Project
To begin working with Apache Camel and GraphQL, we need to set up a Spring Boot-based project with the appropriate dependencies and configuration. The stack combines the robust routing capabilities of Apache Camel with the flexibility of GraphQL APIs, all within the familiar Spring Boot ecosystem.
- Apache Camel (with camel-spring-boot): This serves as the core integration framework. The
camel-spring-bootstarter allows seamless integration with Spring Boot, enabling us to define routes as Spring Beans and take advantage of auto-configuration. - Spring Boot: Provides the base for building production-grade applications quickly. It simplifies dependency management, configuration, and application lifecycle management.
- GraphQL Java Tools: A convenient library that allows the use of `.graphqls` schema files and maps them to resolvers (Java classes). This makes it easy to define a GraphQL schema and implement corresponding resolver logic in Java.
- Java 17+: A modern and stable version of Java that offers performance improvements, better language features (like pattern matching, sealed classes), and long-term support.
To get started, you can either manually create a Maven/Gradle project or use Spring Initializr. Make sure to include dependencies for Spring Web, Apache Camel, and GraphQL. Additional configuration and route definitions will follow in the next sections.
2.1 Add Dependencies (pom.xml)
To begin integrating Apache Camel and GraphQL into your Spring Boot application, update your pom.xml file with the necessary dependencies. These libraries provide support for routing, GraphQL APIs, and JSON data processing.
<!-- pom.xml -->
<dependencies>
<!-- Apache Camel Spring Boot Starter for routing and integration -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>latest__jar__version</version>
</dependency>
<!-- GraphQL Java Kickstart Starter for Spring Boot GraphQL support -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>latest__jar__version</version>
</dependency>
<!-- Jackson Databind for JSON serialization and deserialization -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- Spring Boot Starter Web (optional, for REST endpoints if needed) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok (optional, for cleaner model code with annotations like @Data) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
You can replace latest__jar__version with the latest stable versions from Maven Central. Make sure to also include plugin management and build sections if needed for Spring Boot.
2.2 Creating the Book Model
Next, define a simple Book model class. This class will serve as a Data Transfer Object (DTO) that represents the book entity within both REST and GraphQL APIs.
// Book.java
package com.example.model;
public class Book {
private String id;
private String title;
private String author;
public Book() {}
public Book(String id, String title, String author) {
this.id = id;
this.title = title;
this.author = author;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
This model can be used in your service layer, REST controllers, and GraphQL resolvers. If you choose to use Lombok, you can simplify this class by adding the @Data, @AllArgsConstructor, and @NoArgsConstructor annotations and omitting the boilerplate getters and setters.
2.3 Creating a Service Class
The BookService class acts as a simple in-memory data store and encapsulates the core business logic related to books. It provides methods to fetch all books, fetch a book by ID, and add a new book.
// BookService.java
package com.example.service;
import com.example.model.Book;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class BookService {
// Simulated in-memory storage using a HashMap
private final Map<String, Book> books = new HashMap<>();
// Constructor initializes the book store with some sample data
public BookService() {
books.put("1", new Book("1", "1984", "George Orwell"));
books.put("2", new Book("2", "Brave New World", "Aldous Huxley"));
}
// Returns a list of all books
public Collection<Book> getAllBooks() {
return books.values();
}
// Returns a book by its ID, or null if not found
public Book getBookById(String id) {
return books.get(id);
}
// Adds a new book to the store and returns the added book
public Book addBook(Book book) {
books.put(book.getId(), book);
return book;
}
}
This service is annotated with @Service so that it can be auto-wired into other components like routes or resolvers. In a real-world application, this would be backed by a database or repository.
2.4 Creating REST Endpoints With Camel
Using Apache Camel’s REST DSL, we expose RESTful endpoints and route the requests to service methods. Camel’s fluent API allows for a clean, declarative definition of HTTP operations and their internal processing logic.
// RestApiRoute.java
package com.example.route;
import com.example.model.Book;
import com.example.service.BookService;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
@Component
public class RestApiRoute extends RouteBuilder {
private final BookService bookService;
// Constructor-based dependency injection of the BookService
public RestApiRoute(BookService bookService) {
this.bookService = bookService;
}
@Override
public void configure() throws Exception {
// Set up the REST configuration using servlet component and base path "/api"
restConfiguration()
.component("servlet")
.contextPath("/api")
.bindingMode(org.apache.camel.model.rest.RestBindingMode.json);
// Define REST endpoint for "/books" resource
rest("/books")
.get() // GET /api/books → returns all books
.to("direct:getAllBooks")
.post() // POST /api/books → adds a new book
.type(Book.class)
.to("direct:addBook");
// Route to retrieve all books
from("direct:getAllBooks")
.routeId("getAllBooksRoute")
.bean(bookService, "getAllBooks");
// Route to add a new book
from("direct:addBook")
.routeId("addBookRoute")
.bean(bookService, "addBook");
}
}
2.5 Creating the GraphQL Schema
GraphQL requires a schema definition that outlines the structure of the data, the available queries, and mutations. This schema is typically defined using the Schema Definition Language (SDL) and placed in the src/main/resources/graphql directory. Spring Boot with GraphQL Java Tools will automatically scan and load this file.
Create the file: src/main/resources/graphql/schema.graphqls
type Book {
id: String
title: String
author: String
}
type Query {
books: [Book] # Fetch all books
book(id: String): Book # Fetch a book by its ID
}
type Mutation {
addBook(id: String!, title: String!, author: String!): Book
}
The schema contains:
Booktype: Represents the domain model with fieldsid,title, andauthor.Querytype: Provides two operations:books: Returns a list of all books.book(id: String): Returns a single book based on the provided ID.
Mutationtype: Defines one operation:addBook: Accepts required fieldsid,title, andauthorto create a new book record.
This schema enables you to query and mutate book data via a GraphQL endpoint, which we will now connect using Java resolvers.
2.6 Adding GraphQL Route
Now, create a resolver class that implements the defined GraphQL schema using Java. This class bridges the schema with your service logic and responds to GraphQL queries and mutations.
// GraphQLResolver.java
package com.example.graphql;
import com.example.model.Book;
import com.example.service.BookService;
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import com.coxautodev.graphql.tools.GraphQLMutationResolver;
import org.springframework.stereotype.Component;
import java.util.Collection;
@Component
public class GraphQLResolver implements GraphQLQueryResolver, GraphQLMutationResolver {
private final BookService bookService;
// Constructor injection of BookService
public GraphQLResolver(BookService bookService) {
this.bookService = bookService;
}
// Resolver for the 'books' query
public Collection<Book> books() {
return bookService.getAllBooks();
}
// Resolver for the 'book' query by ID
public Book book(String id) {
return bookService.getBookById(id);
}
// Resolver for the 'addBook' mutation
public Book addBook(String id, String title, String author) {
return bookService.addBook(new Book(id, title, author));
}
}
This class uses GraphQLQueryResolver and GraphQLMutationResolver from the graphql-java-tools library. It automatically maps to the methods defined in your schema.graphqls file by name and parameter.
books(): Maps to thebooksquery.book(id): Maps to thebookquery with a parameter.addBook(id, title, author): Maps to theaddBookmutation and creates a new book object.
The combination of schema + resolver ensures your GraphQL server is fully operational and ready to serve requests through a single endpoint, typically /graphql.
2.7 Main Application Class
This is the entry point for the Spring Boot application. It bootstraps the embedded server (like Tomcat) and initializes all Spring Beans, including your Apache Camel routes and GraphQL resolvers.
// Application.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.8 Code Run and Output
Once your application is fully set up, you can run it using:
./mvnw spring-boot:run
Or if you’re using an IDE like IntelliJ IDEA or Eclipse, you can right-click on Application.java and select “Run”.
2.8.1 REST API Output
After starting the application, test the REST endpoints using tools like Postman, curl, or a browser:
GET http://localhost:8080/api/books— Returns the list of predefined books in JSON format.POST http://localhost:8080/api/books— Allows you to add a new book by sending a JSON payload.
2.8.2 GraphQL Output
Access the GraphQL endpoint (if configured) at:
http://localhost:8080/graphql
You can use tools like:
- Postman with GraphQL support
- GraphiQL UI (if integrated)
- Insomnia for GraphQL testing
Example GraphQL query to fetch all books:
query {
books {
id
title
author
}
}
Example mutation to add a new book:
mutation {
addBook(id: "4", title: "The Hobbit", author: "J.R.R. Tolkien") {
id
title
author
}
}
If everything is configured properly, the GraphQL and REST endpoints should function concurrently, demonstrating the flexibility of Apache Camel in bridging multiple API paradigms.
3. Conclusion
Apache Camel provides a seamless way to integrate REST and GraphQL APIs within the same project. With its routing engine, it decouples the business logic from transport and protocol-specific code, enabling a clean, maintainable architecture. Combining Camel with Spring Boot and GraphQL Java Tools, you can expose flexible APIs with minimal effort and maximum scalability.




