Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

Microservices: Comparing DIY with Apache Camel

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

Share:

    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

    • Create and enrich ServiceNow ITSM tickets with Ansible Automation Platform

    • Expand Model-as-a-Service for secure enterprise AI

    • OpenShift LACP bonding performance expectations

    • Build container images in CI/CD with Tekton and Buildpacks

    • How to deploy OpenShift AI & Service Mesh 3 on one cluster

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    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
    © 2025 Red Hat

    Red Hat legal and privacy links

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

    Report a website issue