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

API-first design with OpenAPI and Red Hat Fuse

July 9, 2019
Jacob Borella
Related topics:
Java
Related products:
Red Hat Fuse

    API-first design is a commonly used approach where you define the interfaces for your application before providing an actual implementation. This approach gives you a lot of benefits. For example, you can test whether your API has the right structure before investing a lot of time implementing it, and you can share your ideas with other teams early to get valuable feedback. Later in the process, delays in the back-end development will not affect front-end developers dependent on your service so much, because it's easy to create mock implementations of a service from the API definition.

    Much has been written about the benefits of API-first design, so this article will instead focus on how to efficiently take an OpenAPI definition and bring it into code with Red Hat Fuse.

    Imagine an API has been designed that is used for exposing a beer API. As you can see in the JSON file describing the API, it's an OpenAPI definition and each operation is identified by an operationId. That will prove to be handy when doing the actual implementation. The API is pretty simple and consists of three operations:

    • GetBeer—Get a beer by name.
    • FindBeersByStatus—Find a beer by its status.
    • ListBeers—Get all beers in the database.

    Keep generated code separate from the implementation

    We don’t want to code all the DTOs and boilerplate code, because that’s very time-consuming and trivial as well. Therefore, we'll use the Camel REST DSL Swagger Maven Plug-in for generating all of that.

    We want to keep the code generated by the swagger plugin separate from our implementation for several reasons, including:

    • Code generation consumes time and resources. Separating code generation from compiling allows us to spend less time waiting and thus more time drinking coffee with colleagues and being creative in all sorts of ways.
    • We don't have to worry that a developer will accidentally put some implementation stuff in an autogenerated class and thus lose valuable work the next time the stub is regenerated. Of course, we have everything under version control, but it's still time-consuming to resolve what was done, moving code, etc.
    • Other projects can refer to the generated artifacts independently of the implementation.

    To keep the generated stub separate from the implementation, we have the following initial structure:

    .
    +-- README.md
    │-- fuse-impl
    │   +-- pom.xml
    │   `-- src
    │       │-- main
    │       │   │-- java
    │       │   `-- resources
    │       `-- test
    │           │-- java
    │           `-- resources
    `-- stub
        │-- pom.xml
        `-- src
            `-- spec
    

    The folder stub contains the project for the generated artifacts. The folder fuse-impl contains our implementation of the actual service.

    Setting up code generation with Swagger

    First, configure the Swagger plugin by adding the following in the pom.xml file for the stub project:

    …
    <dependencies>
      <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-swagger-java-starter</artifactId>
      </dependency>
    …
    </dependencies>
    …
    <plugins>
      <plugin>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-restdsl-swagger-plugin</artifactId>
        <version>2.23.0</version>
        <executions>
          <execution>
            <goals>
              <goal>generate-xml-with-dto</goal><!-- 1 -->
            </goals>
          </execution>
        </executions>
        <configuration>
          <specificationUri><!-- 2 -->
            ${project.basedir}/src/spec/beer-catalog-API.json
          </specificationUri>
          <fileName>camel-rest.xml</fileName><!-- 3 -->
          <outputDirectory><!-- 4 -->
                  ${project.build.directory}/generated-sources/src/main/resources/camel-rest
          </outputDirectory>
          <modelOutput>
            ${project.build.directory}/generated-sources
          </modelOutput>
          <modelPackage>com.example.beer.dto</modelPackage><!-- 5 -->
        </configuration>
      </plugin>
    </plugins>
    ...
    

    The plugin is pretty easy to configure:

    1. The goal is set to generate-xml-with-dto, which means that a rest DSL XML file is generated from the definition together with my Data Transfer Objects. There are other options, including one to generate a Java client for the interface.
    2. specificationUri points to the location of my API definition.
    3. The name of the rest DSL XML file to generate.
    4. Where to output the generated rest DSL XML file. If placed in this location, Camel will automatically pick it up if included in a project.
    5. Package name for the DTOs.

    In pom.xml, we also need to change the location of the source and resource files for the compiler. Finally, we need to copy the API specification to the location we chose previously. This isn't described here because it's known stuff, but you can refer to the source code for the specifics as needed. Now, we're ready to generate the stub for the REST service.

    So far, we have the following file structure in the stub project:

    .
    `-- stub
        +-- pom.xml
        `-- src
            `-- spec
                `-- beer-catalog-API.json
    

    Run mvn install in the stub dir and the stub is automatically generated, compiled, put in a jar file, and put into the local Maven repository. The DTOs are generated in the package we chose previously. Furthermore, an XML file is created for the REST endpoint.

    Contents of file stub/target/generated-sources/src/main/resources/camel-rest/camel-rest.xml:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <rests xmlns="http://camel.apache.org/schema/spring">
        <restConfiguration component="servlet"/>
        <rest>
            <get id="GetBeer" uri="/beer/{name}">
                <description>Get beer having name</description>
                <param dataType="string" description="Name of beer to retrieve" name="name" required="true" type="path"/>
                <to uri="direct:GetBeer"/>
            </get>
            <get id="FindBeersByStatus" uri="/beer/findByStatus/{status}">
                <description>Get beers having status</description>
                <param dataType="string" description="Status of beers to retrieve" name="status" required="true" type="path"/>
                <param dataType="number" description="Number of page to retrieve" name="page" required="false" type="query"/>
                <to uri="direct:FindBeersByStatus"/>
            </get>
            <get id="ListBeers" uri="/beer">
                <description>List beers within catalog</description>
                <param dataType="number" description="Number of page to retrieve" name="page" required="false" type="query"/>
                <to uri="direct:ListBeers"/>
            </get>
        </rest>
    </rests>
    

    The important thing to note is that each REST operation is routing to a uri named direct:operatorId, where operatorId is the same operator as in the API definition file. This enables us to easily provide an implementation for each operation.

    Providing an implementation of the API

    For the example implementation, we chose Fuse running in a Spring Boot container to make it easily deployable in Red Hat OpenShift.

    Besides the usual boilerplate code, the only thing we have to do is add a dependency to the project containing the stub in our pom.xml file of the fuse-impl project:

        <dependency>
          <groupId>com.example</groupId>
          <artifactId>beer</artifactId>
          <version>1.0</version>
        </dependency>
    

    Now we're all set, and we can provide our implementation of the three operations. As an example of an implementation, consider the following.

    Contents of fuse-impl/src/main/java/com/example/beer/routes/GetBeerByNameRoute.java:

    package com.example.beer.routes;
    
    import org.apache.camel.Exchange;
    import org.apache.camel.Processor;
    import org.apache.camel.builder.RouteBuilder;
    import org.apache.camel.model.dataformat.JsonLibrary;
    import org.springframework.stereotype.Component;
    
    import java.math.BigDecimal;
    import com.example.beer.service.BeerService;
    import com.example.beer.dto.Beer;
    import org.apache.camel.BeanInject;
    
    @Component
    public class GetBeerByNameRoute extends RouteBuilder {
      @BeanInject
      private BeerService mBeerService;
    
      @Override
      public void configure() throws Exception {
        from("direct:GetBeer").process(new Processor() {
    
          @Override
          public void process(Exchange exchange) throws Exception {
            String name = exchange.getIn().getHeader("name", String.class);
            if (name == null) {
              throw new IllegalArgumentException("must provide a name");
            }
            Beer b = mBeerService.getBeerByName(name);
    
            exchange.getIn().setBody(b == null ? new Beer() : b);
          }
        }).marshal().json(JsonLibrary.Jackson);
      }
    }
    

    Here we inject a BeerService, which holds information about the different beers. Then we define a direct endpoint, which provides the endpoint, to which the REST call is routed (remember the operationId mentioned earlier?). The processor tries to look up the beer. If no beer is found, an empty beer object is returned. To try the example, you can run:

    cd fuse-impl
    mvn package
    java -jar target/beer-svc-impl-1.0-SNAPSHOT.jar
    #in a separate terminal
    curl http://localhost:8080/rest/beer/Carlsberg
    {"name":"Carlsberg","country":"Denmark","type":"pilsner","rating":5,"status":"available"}
    

    We might have to do this over and over again. In that case, we can create a Maven archetype for the two projects. Alternatively, we can clone a template project containing all the boilerplate code and do the necessary changes from there. That will be a bit more work, though, because we'll have to rename Maven modules as well as Java classes, but it's not too much of a hassle.

    Conclusion

    With an API-first approach, you can design and test your API before doing the actual implementation. You can get early feedback on your API from the people using it, without having to provide an actual implementation. In this way, you can save time and money.

    Going from design to actual implementation is easy with Red Hat Fuse. Just use the Camel REST DSL Swagger Maven Plugin to generate a stub and you are set for providing the actual implementation. If you want to try it for yourself, use the example code as a starting point.

    Last updated: June 23, 2023

    Recent Posts

    • Trusted software factory: Building trust in the agentic AI era

    • Build a zero trust AI pipeline with OpenShift and RHEL CVMs

    • Red Hat Hardened Images: Top 5 benefits for software developers

    • How EvalHub manages two-layer Kubernetes control planes

    • Tekton joins the CNCF as an incubating project

    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.