Enterprise grade Java.
You'll read about Conferences, Java User Groups, Java, Integration, Reactive, Microservices and other technologies.

Tuesday, December 23, 2014

Riding Camel on Java EE 7 - REST Services with Swagger Documentation

11:05 Tuesday, December 23, 2014 Posted by Markus Eisele
, , ,
Camel comes with a bunch of features out of the box. One of them is the Swagger integration. Unfortunately, most of the already-there features heavily rely on Spring. But this should not stop us from using them in plain Java EE 7 applications, because it sometimes is just the more lightweight variant of doing things. But I don't want to start a discussion about this again. Instead, I think that there is a technology choice for all situations and if you run across a project you just want to use Camel with Java EE 7 and you need REST services and want to document them with Swagger, this is the right post for you.

Bootstrapping Camel in EE 7
The first thing you need, is to bootstrap Camel in a singleton startup bean. I already wrote an article, about how to do this. The other option is to actually use the wildfly-camel subsystem which is also available, but this requires you to be on JBoss WildFly 8.x.

Swagger And Camel Rest Dependencies
The Swagger integration in Camel as of today is supported for Spring applications only. So, to make this work, we do have to implement a bit and configure a bit more than usual. But I promise, that it is not too complicated and done in a minute. Let's start:
First thing to add to the basic Camel EE 7 example are the additional dependencies for camel:

         <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-servlet</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-metrics</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-swagger</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-jackson</artifactId>
        </dependency>

Returning The Camel Context For Swagger
If we can't use what is there, we need to implement our own CdiRestSwagger-Camel context lookup. There are some things cooking for upcoming Camel versions, but for now we have to do it on our own. Which is surprisingly simple, because we need to overwrite one method of the  RestSwaggerApiDeclarationServlet. And this does nothing else than simply return the injected CdiCamelContext.

public class CdiRestSwaggerApiDeclarationServlet extends RestSwaggerApiDeclarationServlet {

    @Inject
    CdiCamelContext context;

    @Override
    public CamelContext lookupCamelContext(ServletConfig config) {
        return context;
    }
}

Some Further Configuration
We're not done yet. You still have some more configuration to do. As Camel is designed to run in many different environments and there is no specific Java EE 7 version, it still rely on web.xml configuration for the mapping servlets. Please pay extra attention to the CdiRestSwaggerApiDeclarationServlet init-parameters. In this simple example, I did not bother with finding them out, but still rely on them. So, depending on the final name of your application that you set in the Maven build, this needs to be tweaked.

 <context-param>
        <param-name>contextConfigLocation</param-name>
        <!-- to use Java DSL -->
        <param-value>classpath:camel-config.xml</param-value>
 </context-param>

    <!-- to setup Camel Servlet -->
    <servlet>
       <display-name>Camel Http Transport Servlet</display-name>
        <servlet-name>CamelServlet</servlet-name>
        <servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet<load-on-startup>1</load-on-startup>
    </servlet>

    <!-- to setup Camel Swagger api servlet -->
    <servlet>
        <!-- we are using our own swagger-cdi binding servlet -->
        <servlet-class>org.apache.camel.component.swagger.CdiRestSwaggerApiDeclarationServlet
        <init-param>
            <param-name>base.path</param-name>
            <param-value>http://localhost:8080/camel/rest</param-value>
        </init-param>
        <init-param>
            <param-name>api.path</param-name>
            <param-value>         http://localhost:8080/camel/api-docs          </param-value>
        </init-param>
        <init-param>
            <param-name>api.version</param-name>
            <param-value>1.2.3</param-value>
        </init-param>
        <init-param>
            <param-name>api.title</param-name>
            <param-value>User Services</param-value>
        </init-param>
        <init-param>
            <param-name>api.description</param-name>
            <param-value>Camel Rest Example with Swagger that provides an User REST service</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>

    <!-- swagger api declaration -->
    <servlet-mapping>
        <servlet-name>ApiDeclarationServlet</servlet-name>
        <url-pattern>/api-docs/*</url-pattern>
    </servlet-mapping>

    <!-- define that url path for the Camel Servlet to use -->
    <servlet-mapping>
        <servlet-name>CamelServlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

    <!-- enable CORS filter so people can use swagger ui to browse and test the apis -->
    <filter>
        <filter-name>RestSwaggerCorsFilter</filter-name>
        <filter-class>org.apache.camel.component.swagger.RestSwaggerCorsFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>RestSwaggerCorsFilter</filter-name>
        <url-pattern>/api-docs/*</url-pattern>
        <url-pattern>/rest/*</url-pattern>
    </filter-mapping>

Enough Configuration - To The Logic!
When you're done with that, you need some logic. The example I'm using here was taken from the official Camel examples and is called camel-example-servlet-rest-tomcat. Please note, that this example contains both, a XML DSL based definition and the Java DSL based definition of the rest-service. I only used the Java DSL and specifically the route defined in the UserRouteBuilder class.
Make sure to add a @Named annotation to the UserService and the User and add the route from the UserRouteBuilder to your startup bean.

   context.addRoutes(new UserRouteBuilder());

That is it. Now you can browser your API by accessing http://localhost:8080/camel/api-docs. If you want to use the Swagger UI you have to add it to your application. The example application contains everything in the build section, that is needed to do this. So, have a look at the complete GitHub project to find out how to browse the API with the Swagger UI.