JAX-RS REST with Swagger in IBM Integration Designer

We have seen over the last 2-3 years an evolution in the way how we are interacting with our services.  This is thanks to mobile devices which don’t have the same processing power like our servers in the data centers and also bandwidth data restrictions might play here an important factor. Enterprise Services in a Service Oriented Architecture use(d) HTTP/SOAP as an interoperability protocol. A lot of software products have Webserviece APIs via SOAP but due to the growing business demand to go mobile these interfaces don’t play very well with our devices. Besides the already mentioned factors the computation cost of SOAP message data serialization is notable, that’s why HTTP/JSON has taken over the Mobile and Cloud world. Though JSON has many obvious advantages as a data interchange format – it is lightweight, human readable, well understood, and typically performs well – it also has its issues (I will save this for another article).

To everyone working with Web services the standard definition file is a WSDL file which basically is a services contract between client and server with well defined objects and schemas, containing either document-oriented or procedure-oriented information. In WebSphere Integration Developer (WID) or now IBM Integration Designer (IID) you can easily create a Web service HTTP/SOAP Binding with a WSDL file or use a HTTP Binding with a builtin JSONDataHander to expose your service as a RESTful service in a couple of clicks. Sadly at this point no one knows how to use our RESTful API and you have to spend time to write additional documentation or define a WADL file, which is incredibly time consuming to create descriptions with.

Fortunately there is swagger.io a framework to help fill the gap. Swagger is a specification for documenting REST APIs. It specifies the format (method, url and representation) to describe REST Web services. It provides also tools to generate the documentation from application code.

IBM BPM 8.5.x  is using WAS 8.5.x as runtime platform, which as part of the official EE6 platform supports JAX-RS. Integration Designer doesn’t support neither JAX-RS nor Swagger as part of the auto-generated Bindings. There is a RFE for this feature. Luckily it supports Web Application development and that’s what I’m going to use to create a JAX-RS Web Interface, declare swagger annotations and call out via a SCA Reference Partner to my Mediation.

We are going to start with the interface, objects and the Stand-alone Reference component. The Name of the standalone ReferencePartner is “CarPartner”.

jaxrs-1

 

jaxrs-1a

Now let’s create a Web Application Module (war)

jaxrs-1b

and link it to our Mediation Module

jaxrs-1c

When cleaning/building your workspace, IID compiles your application so any modifications done in the default WEB module will be erased, that’s another reason for using a separate custom Web Module. From here on, you can start creating your JAX-RS Interface and write the necessary code to initialize swagger and also make the connection to your SCA Component.

In order to give swagger the knowledge of the structure of the schema objects in use for the JAX-RS interface we have to generate JBAX-POJOs/SDO implementation classes because swagger is not designed to understand XSDs. You can do that by switching from default (Business Integration) perspective to Java perspective and use the builtin wizard to generate Java classes.

jaxrs-1d

If you are using Maven or Gradle you can get the swagger libraries from the Maven repo. For the purpose of this walk through I have extracted the necessary jar files from the POM.XML via

mvn install dependency:copy-dependencies

and copied them into the WAR/lib folder. There are also two additional libraries for the CORS filter support which are needed to grant access to swagger-ui.

jaxrs-1e

Let’s assemble everything. There are various ways to initialize swagger. First update the web.xml with the following entries:

<servlet>
<description>
This is the description for the sample servlet
</description>
<display-name>Gateway</display-name>
<servlet-name>com.mygateway.GatewayApplication</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>com.mygateway.GatewayApplication</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

 

Create an Application class with the following entries: (more info can be obtained in the swagger documentation)

package com.mygateway;

import io.swagger.jaxrs.config.BeanConfig;
import io.swagger.jaxrs.listing.ApiListingResource;
import io.swagger.jaxrs.listing.SwaggerSerializers;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;

public class GatewayApplication extends Application {

 public GatewayApplication() {
 BeanConfig beanConfig = new BeanConfig();
 beanConfig.setTitle("PoT SWAGGER - REST GATEWAY");
 beanConfig.setDescription("Test API REST Interface with Swagger Annotations");
 beanConfig.setVersion("0.0.1");
 beanConfig.setSchemes(new String[] { "http" });
 beanConfig.setHost("localhost:9080");
 beanConfig.setBasePath("/Gateway/rest");
 beanConfig.setResourcePackage("com.mygateway");
 beanConfig.setScan(true);
 beanConfig.setPrettyPrint(true);
 }

 public Set<class<?>> getClasses() {
 Set<class<?>> classes = new HashSet();

 //JAX-RS interface
 classes.add(GatewayService.class);
 //Add Swagger initialisation classes
 classes.add(ApiListingResource.class);
 classes.add(SwaggerSerializers.class);

 return classes;
 }
}

My JAX-RS class (GatewayService.java) has the same 3 operations as my SCA Interface. Once the HTTP call is initialized a call-out is made via the SCA Partner “CarPartner” to my Mediation and the response is feed though a SDO/JSON data formatter.

@Api(value = "/cars", description = "RESTful API to interact with Car Servcie.")
@Path("/cars")
@Stateless
public class GatewayService extends Application {

 @ApiOperation(value = "Get Car by ID", notes = "Get model details by ID", responseContainer = "Car", response = Car.class)
 @GET
 @Path("/{id}")
 @Produces(MediaType.APPLICATION_JSON)
 public Response getById(
 @ApiParam(value = "Car ID", required = true) @PathParam("id") int id)
 throws Exception {

 // Invoke SCA Stand-alone Reference Partner
 Service service = (Service) ServiceManager.INSTANCE.locateService("CarPartner");
 DataObject car = (DataObject) service.invoke("getCarById",Integer.valueOf(id));
 DataObject res = (DataObject) car.get(0);

 //Use SDO to JSON Converter
 com.ibm.bpe.message.JsonConverter jc = com.ibm.bpe.message.JsonConverter.getInstance();
 String resp = jc.convertObject2JSON(res);

 if (res != null) {
 return Response.ok(resp).build();
 }
 return Response.status(Response.Status.NOT_FOUND).build();
 }
...
...
}

The response class definition points to the SDO Java implementation generated though the wizard.

 response = Car.class

You might ask why I’m using the generated Java classes only for swagger presentation purpose? Well, many ways lead to Rome. You could use for the Response following approach:  EMF EObjects or SDO EDataObjects to Java POJO to JSON, or create a dynamic EMF model from XSDs, or serializae JSON to XML to SDO. I still believe a simple SDO/JSON transformation will give the best performance. On the other hand swagger needs a strong typed definition of your objects, whereby the DataObject implementation is dynamic, hence we use the generated classes for the swagger presentation layer.

After the deployment of the APP to Process Server we can invoke the REST service.

jaxrs-1g

Now it’s time to see the service definition in my local swagger-ui.

swagger2

Swagger-ui with Websphere Application Server

To deploy the swagger-ui on WebSphere Application Server get the source code from github first. Create a Simple Web Project in Eclipse and copy the content of the ‘dist’ folder from the zip archive into WebContent folder. Make sure you have the WebSphere Development Tools plugin installed in Eclipse. You can find it in the Eclipse Marketplace.

Now set the root context to /swagger in ibm-web-ext.xml. Export the project as WAR and deploy on the Application Server.

swagger-ui1

 

To point by default to your own RESTful API with swagger annotations change the url in the index.html file.

swagger-ui2