Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • Guided learning
      Receive custom learning paths powered by our AI assistant.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

Microservices: Comparing DIY with Apache Camel

November 7, 2016
James Falkner
Related topics:
Developer toolsJavaKubernetesMicroservices
Related products:
Developer ToolsetRed Hat FuseRed Hat JBoss Enterprise Application PlatformRed Hat OpenShift Container Platform

    Microservices are currently enjoying immense popularity. It is rare to find a tech conference without at least a few mentions of them in corridor conversations or titles of talks, and for good reason: microservices can provide a path to better, more maintainable, higher quality software delivered faster. What's not to love?

    Of course there are the "negatives" and details in the implementation of microservices that can trip up even the most seasoned architect-developer, but at the same time we are collectively learning from mistakes and creating or reusing fantastic open source projects and products that can help smooth over those rough bits.

    One such project is Apache Camel (and Fuse, its Red Hat-supported distribution.) Created way before the microservices revolution, Apache Camel was born to ease integration of disparate computing systems by implementing well-tested enterprise integration patterns (EIPs) and supplying a developer-friendly interface for writing code to do the integration.

    Microservices are by their nature an integration problem, where you have many decoupled services that need to work together. In working with Camel over the last few months, I have observed that it gets most of its credit from its large collection of components that can talk the language of many existing systems. But in the microservices context, what's even more interesting to me are the EIPs and how they align very well with microservices architectures (I am not the first to observe this, but I don't think it gets enough credit!)

    In this post I'm going to show you how I used Camel to implement a microservice pattern, the API Gateway, replacing hand-crafted code with a much more elegant solution (in my opinion.) The example application for this is a demo I developed for making a more eye-catching and real-world version of the excellent Red Hat Developers Hello World Microservices demo, while still being able to demonstrate various aspects of microservices-oriented applications (such as the use of API Gateways, call tracing, circuit breakers, CI/CD pipelines, etc). It is a retail store demo, with typical store elements such as a product catalog, inventory service, shopping cart, etc.

    In this application, the API gateway serves to provide a single, load-balanced point of entry for clients like mobile apps, and in some cases to aggregate data from multiple microservices into a single result. There are benefits and drawbacks to including this aggregation logic in the API Gateway, and it may make sense to separate them, especially if you include more detailed business logic in the aggregation, but for my purposes, I had no need for any actual business logic, so I decided to combine them. Your mileage may vary.

    The general arrangement of services and their runtimes is illustrated below:

    CoolStore Microservices Demo Architecture
    CoolStore Microservices Demo Architecture
    CoolStore Microservices Demo Architecture

    Here, we have several microservices providing the retail store services running on an OpenShift Container Platform, SSO for authentication using Red Hat SSO, call metrics with Hystrix+Turbine and a UI for our customers (thanks PatternFly!) The UI shows product names, descriptions, prices, and availability of products across the various brick-and-mortar stores of the shop. The idea is that the inventory service is a legacy backend mainframe, the pricing service is a modern rules-driven thing to dynamically calculate discounts, taxes, etc and the catalog is some other system. To construct the initial UI, the client could make individual calls to each (exposing each on the internet, requiring multiple round-trips to get the data, etc), but instead we introduce the API Gateway to mediate and aggregate data, and provide a single response. So the simple call to "give me the products to show" looks like:

    CoolStore product REST call sequence
    CoolStore product REST call flow
    CoolStore product REST call sequence

    Here, the call to the /api/products endpoint requires the gateway to first fetch the list of products, then for each one, fetch its availability (via the inventory service), aggregate the results into a single JSON blob and return to the client.

    Cut 1: Brute force using a for() loop:

    I didn't actually implement this, but you can imagine what it would look like via this pseudo-code:

    List<Product> products =
      HttpClient.get("http://catalog-service/api/products").convertToProductList();
    
    forEach(Product product : products) {
      Inventory inventory =
        HttpClient.get("http://inventory-service/api/availability/" + product.itemId)
          .convertToInventory();
      product.setInventory(inventory);
    }
    return products;

    It's short, easy to understand code, but not very resiliant to timeouts/failures, and is completely serial in execution.

    Cut 2: Concurrency and Resilience

    I started here for the implementation, taking the simple code from Hello World MSA's API Gateway and bolting on my attempt at using Java Concurrency to handle the async REST calls and stream operations to handle the aggregation:

    final CompletableFuture<List<Product>> productList = CompletableFuture.supplyAsync(() ->
     feignClientFactory.getPricingClient().getService().getProducts(), es);
    
    return productList.thenCompose((List<Product> products) -> {
        List<CompletableFuture<Product>> all =
          products.stream()
          .map(p -> productList.thenCombine(
            CompletableFuture.supplyAsync(() ->
              feignClientFactory.getInventoryClient().getService().getAvailability(itemId), es),
              (pl, a) -> {
                p.availability = a;
                return p;
              }
            )
          )
          .collect(Collectors.toList());
    
          return CompletableFuture.allOf(all.toArray(new CompletableFuture[all.size()]))
            .thenApply(v -> all.stream()
              .map(CompletableFuture::join)
              .collect(Collectors.toList()
            )
          );
        }
    ).get();

    This is better functionally, but IMO Java Concurrency is way too "wordy" and this is not very intuitive or readable. It's still essentially a for() loop, but doing all the network calls asynchronously, and using Feign to make a more type-safe REST call, and Hystrix for circuit breaking when the underlying inventory service is too slow or dead.

    Cut 3: Camel

    Camel's DSL for REST looked very promising, and when I learned there were components for Hystrix and implementations of EIPs for aggregation, I thought I'd give it a shot. The Enricher EIP in particular sounded exactly like what I was doing:

    "The Content Enricher uses information inside the incoming message (e.g. key fields) to retrieve data from an external source. After the Content Enricher retrieves the required data from the resource, it appends the data to the message." - from Enterprise Integration Patterns

    dataenricher

    After trial and error (but not much!), here is what's currently in the codebase for this API's Camel route:

    .hystrix()
      .to("http://catalog-service:8080/api/products")
    .onFallback()
      .to("direct:productFallback")
    .end()
    .unmarshal()
    .split(body()).parallelProcessing()
    .enrich("direct:inventory", new InventoryEnricher())

    Again, still essentially a for() loop (which incidentally could be improved by making the inventory service handle batch requests), but IMO much more compact and elegant. The "magic" aggregation happens by split()'ing the list of products into a stream and then enrich()'ing the stream by fetching the inventory (inside another route), setting the inventory into the product object via the InventoryEnricher, and returning the resulting enriched list of products.

    The route to fetch the inventory also circuit breaks the inventory service using Hystrix:

    .hystrix()
      .setHeader("itemId", simple("${body.itemId}"))
      .setHeader(Exchange.HTTP_URI, simple("http://inventory-service:8080/api/availability/${header.itemId}"))
      .to("http://inventory-service")
    .onFallback()
      .to("direct:inventoryFallback")
    .end()
    .unmarshal()

    The fallbacks in this case are additional Camel routes which do the same as Hello World MSA, namely generate a hard-coded substitute value:

    .transform().constant(new Inventory("0", 0, "Local Store", "http://redhat.com"))

    In summary, aside from Camel's collection of integration code for Facebook, Twitter and various other modern services, it implements a ton of patterns that are super useful for connecting microservices together without having to re-invent the wheel. Ride on!

    Future improvements

    • Caching service calls (e.g. using Camel Cache)
    • Improving batch capabilities of the underlying services
    • Adding Feign-like typesafe API infrastructure
    • Integrating other Red Hat OpenShift xPaaS services such as Fuse and BRMS
    • More domain separation (currently the API gateway must know too much about the catalog and cart structures)

    Feedback and contributions are always welcome!

    Last updated: November 9, 2023

    Recent Posts

    • Installing Red Hat Enterprise Linux 10 from a bootc image with bootc

    • Why your database benchmarking data is probably wrong (and how I fixed mine)

    • Type what you want to break: AI-assisted chaos engineering with Krkn

    • Understanding evaluation collections in EvalHub

    • An overview of confidential containers on OpenShift bare metal

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer tools
    • Interactive tutorials
    • API catalog

    Quicklinks

    • Learning resources
    • E-books
    • Cheat sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site status dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2026 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Chat Support

    Please log in with your Red Hat account to access chat support.