Enterprise Java

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-boot starter 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:

  • Book type: Represents the domain model with fields id, title, and author.
  • Query type: Provides two operations:
    • books: Returns a list of all books.
    • book(id: String): Returns a single book based on the provided ID.
  • Mutation type: Defines one operation:
    • addBook: Accepts required fields id, title, and author to 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 the books query.
  • book(id): Maps to the book query with a parameter.
  • addBook(id, title, author): Maps to the addBook mutation 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:

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.

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button