One of the most used terms these days is API Economy. It is a vast domain that covers the exposure and invocation of services from and to anywhere. At the center of the API Economy are RESTful APIs because they are, by nature, language-neutral and by far the most widely used type of API today.

Liberty supports the creation and deployment of REST APIs in a variety of forms (JAX-RS, Java EE servlet, OSGi web apps, REST Handler, etc) but, until recently, there was not an easy way of exposing all these REST assets from your Liberty instance. This article will go over the new capabilities available in Liberty to close this gap.

The API discovery feature in Liberty

Starting with Liberty v8.5.5.8 we added a new feature called apiDiscovery-1.0. This feature aggregates the Swagger-based definitions from all deployed applications (including runtime endpoints) into a single Swagger document, which can be consumed in native JSON or YAML formats or through our Swagger User Interface.

If you don’t have the apiDiscovery-1.0 feature in your Liberty installation you can pull it from the repository by running the command:

wlp/bin installUtility install apiDiscovery-1.0

The first release of this feature, in Liberty v8.5.5.8, focused on exposing pre-generated Swagger documents in JSON format by searching for a swagger.json file inside the META-INF folder of every deployed web module. All these documents are aggregated internally to produce a single Swagger definition, available through a new Liberty REST endpoint at https://<host>:<https_port>/ibm/api/docs.

Here is a sample of minimal configuration needed in your server.xml in order to reach that endpoint:

<server>
    <featureManager>
        <feature>apiDiscovery-1.0</feature>
    </featureManager>

    <httpEndpoint id="defaultHttpEndpoint"
                  host="*"
                  httpPort="8010"
                  httpsPort="8020"/>

    <keyStore id="defaultKeyStore" password="Liberty"/>
  
    <basicRegistry id="basic" realm="ibm/api">
        <user name="bob" password="bobpwd" />
    </basicRegistry>
</server>

This JSON definition is useful for API Management solutions or any graphical user interface that wants to display the definitions of those RESTful APIs. The following diagrams depicts this relationship:


app_diagram

Liberty’s new Swagger User Interface

In fact, this is exactly what our Swagger User Interface (based on the Swagger UI open source version) does. It renders the aggregated definition from /ibm/api/docs and displays an attractive human-friendly UI at https://<host>:<https_port>/ibm/api/explorer:


explorer_screenshot

Developers familiar with StrongLoop’s Explorer will appreciate the design decision of keeping the UIs consistent at the /explorer endpoint.

From this user interface, just like the open source version and StrongLoop’s version, you can view all RESTful endpoints and actually invoke them right from your browser by filling in the corresponding fields and clicking the Try it out! button. It’s a handy client built into your browser. Another nice feature of our UI, which is not available in other Swagger renderings, is a filter box that lets you focus on the applications you really care about. If, in the example above, I typed /ibm/api/markham/traffic, only the APIs for the Traffic application would be shown in the UI.

From the screenshot above you’ll notice that Liberty’s JMX Connector APIs are also appearing. These APIs were contributed to our API discovery aggregator through our OSGi SPI, com.ibm.wsspi.rest.api.discovery.APIProvider. This very simple interface has a single method, called getDocument, which allows OSGi bundles (web bundles or regular bundles) to contribute REST API definitions into the aggregator.

So if you enable apiDiscovery-1.0 and any internal Liberty runtime that exposes REST APIs (restConnector-1.0, collectiveController-1.0, etc), you will see those APIs in both the aggregated document (/ibm/api/docs) and in the UI (/ibm/api/explorer)! This is also valid for any extensions of Liberty, where their bundles can similarly expose their REST APIs through this SPI.

Besides <webModule>/META-INF/swagger.json and the SPI, using Liberty v8.5.5.8 you also specify another location of your pre-generated Swagger definition by using the webModuleDoc configuration element, a child of apiDiscovery:

<apiDiscovery>
   <webModuleDoc contextRoot="/30ExampleServletInEar" docURL="/swagger.json" />	
   <webModuleDoc contextRoot="/custom" docURL="http://petstore.swagger.io/v2/swagger.json" />
</apiDiscovery>

The first entry, for web module /30ExampleServletInEar, is specifying that a swagger.json is available relative to its context root, therefore at /30ExampleServletInEar/swagger.json, while the second entry, for web module /custom, is specifying the absolute URL of a remote document repository.

The next few Beta releases after Liberty v8.5.5.8 packed a lot more good stuff! Let’s go through some of them.

New Liberty beta functionality

JAX-RS 1.1/2.0 and Swagger annotation support

We now support auto-generation of Swagger definitions from JAX-RS and Swagger annotations! This is a very important feature, since it supports the famous bottom-up development where the documentation comes from the code itself. Just enable apiDiscovery-1.0, drop your JAX-RS application into the dropins directory (with either jaxrs-1.1 or jaxrs-2.0 enabled) and watch your APIs come out inside /ibm/api/explorer!

YAML support

The Liberty REST API Discovery framework now interchangeably supports both JSON and YAML formats. You can provide either format and query either format; it all merges and renders perfectly! This means you can now provide Liberty with your swagger.json OR swagger.yaml document inside <webModule>/META-INF, and also use an Accept header of application/yaml when querying /ibm/api/docs and you’ll be returned the aggregated Swagger 2.0 document in YAML format!

You can also continue to use the /ibm/api/explorer as before, regardless of whether some documents are being provided as JSON and other as YAML.

Stub merging

You can now provide a swagger.json or swagger.yaml document inside <webModule>/META-INF/stub and Liberty’s REST API Discovery framework will automatically merge those contents with any JAX-RS annotations that we find. This is useful for the scenarios where your web module has regular servlets (non JAX-RS) that you want to document in addition to any JAX-RS endpoints. You can also use this methodology to augment your existing annotations with extra information such as security constraints.

Collective aggregation and Explorer

There is now a collective-wide Swagger 2.0 document of your REST APIs. Just add apiDiscovery-1.0 to your collective controller and to any collective member that wants to expose REST APIs, and when you query /ibm/api/collective/docs in the collective controller you will see a Swagger 2.0 document that aggregates all of the REST APIs being exposed in the collective!

We also have its visual counterpart, available at /ibm/api/collective/explorer. It is very similar to /ibm/api/explorer, except that this endpoint is only available in the Liberty collective controller. It will also show all REST APIs that are available from any of the members of that Liberty collective. The filter box for the collective UI also has been enhanced to allow filtering based on collective member ID (a comma-separated tuple of the member’s hostName, URL-encoded wlp/usr path, and serverName).

WebSocket subscription

You can now subscribe to receive real-time updates on the REST APIs of a Liberty server. This means that you can instantly know if a new application has been deployed with new REST endpoints, or if an existing set of endpoints has been dynamically removed. Simply subscribe to the /ibm/api/docs/subscription endpoint and you’ll receive a WebSocket URL which you can open and listen for updates. You can also subscribe for collective-wide notifications by calling /ibm/api/collective/docs/subscription on the collective controller.

Context root document serving

Any web module in Liberty that is providing Swagger 2.0 documentation through any means (i.e. annotations, pre-generated, stub merging, etc) can now directly reach the documentation by invoking <webModule_contextRoot>/swagger.json or <webModule_contextRoot>/swagger.yaml. Except in cases where the application has explicitly blocked access to it, the REST API Discovery framework auto-detects this request from the web container and automatically responds with the Swagger 2.0 document. This provides the exact same effect as querying /ibm/api/docs?root=<webModule_contextRoot>.

For more information please visit Knowledge Center.

32 comments on"Exposing WebSphere Liberty REST APIs with Swagger"

  1. Luigi Biai July 11, 2018

    Hi Arthur,
    thanks a lot for your article, but I am not able to display the REST APIs doc following your tutorial.
    My project is composed by an EAR and JAXRS REST APIs involves in 3 projects:
    – War project with the web.xml file and JaxRs Application class with the method getSingletons that returns all resources.
    – Java jar file with interfaces for rest resources. The interfaces contain the JAX-RS annotations
    – Java jar file with the resource implementation, each class extends the interface
    Seems that apiDiscovery is not able to detect the resources.
    If I create only one project with all resources inside it, the APIs are discovered well and all, but I need to use the scenario below.
    Thanks a lot for your help

    • Arthur De Magalhaes July 17, 2018

      Hey Luigi,
      Thanks for your feedback! Unfortunately, as you noted, the annotation aggregation of this feature was only works when the resources are inside the same project. If you want keep your project structure you could add a YAML or JSON Swagger file (static doc) to your WAR file, which would expose your APIs correctly. You can do that by putting all the resources in a single project, grabbing the output from api/docs, then saving that in your WAR – then you can go back to the original structure.

      By the way, have you checked out the new MicroProfile OpenAPI feature? https://openliberty.io/blog/2018/05/22/microprofile-openapi-intro.html

      Thanks,
      Arthur

  2. Alon Amiramov January 22, 2018

    Dear Arthur,
    First of all thank you for your post.
    Second, when im trying to run my JVM server with the apiDiscovery feture that i included in my server.xml file, my CICS procedure facing a lot of Dumps and errors which disable the proper behavior of the system.
    Can you please tell me what do i need to implement before i enabled the apiDiscovery feature and what do i need to implement afterwards ? Because I think that i miss some step for making this work..
    The things that i done :
    1. Enabled apiDiscovery feature in server.xml file.
    2. Created Swagger.json file under the META-INF directory in my service project.
    That’s it.
    Thak you very much.

  3. Hello Arthur,

    I configured apiDiscovery but I don’t see apis being discovered. I’m using WebSphere Liberty 8.5.5.9. The logs aren’t helping. Any pointers you can give?

    Thanks
    Prajakta

    • Arthur De Magalhaes June 29, 2016

      Hi Prajakta,

      The most common issue is having duplicate method names within your jaxrs app (ie: same method in 2 different resources). Do you have that? Can you offer more information about your app? (how is it structured, how many resources, are you using web.xml or purely annotations, etc)

  4. Hi,

    I am using WAS 8.5.5.0, and want to add swagger to the REST service.
    Can i add swagger? What are the other options with this WAS version?

    thanks in advance

    • Arthur De Magalhaes May 16, 2016

      Hi Rocky. Unfortunately WAS 8.5.5.0 does not have any native Swagger support, as it started with Liberty 8.5.58 and 8.5.5.9.

      However, you can integrate our open source “offline swagger processor” (https://github.com/WASdev/tool.swagger.docgen) into your build system to extract a Swagger definition (either JSON or YAML) from your applications, using the exact same logic as Liberty uses.

      Thanks,
      Arthur

  5. Hi Arthur, great stuff you are presenting here 🙂 One question though, how can you exclude the /IBMJMXConnectorREST in Liberty from your Swagger docs? I really wouldn’t want to expose that one. Br, Hans

    • Arthur De Magalhaes April 26, 2016

      Thanks Hans! Be sure to check out the newest blog about this topic (with videos), at https://developer.ibm.com/wasdev/blog/2016/04/13/deploying-swagger-enabled-endpoints-websphere-liberty-bluemix-api-connect/

      At the moment we don’t have a mechanism to automatically exclude runtime endpoints, such as the jmx connector, but that’s definitely on our radar and being considered.

      What you can do is take advantage of our multi-cardinality query param callled “root”. So for example, if you have 2 apps, with corresponding context roots of /myApp1 and /myApp2, you can call “/ibm/api/docs?root=/myApp1&root=/myApp2” and the Swagger 2.0 doc from that call will only contain those 2 apps, nothing else.

      The exact same filtering is available in the UI side by using the filter input box, where you can type in “/myApp1, /myApp2”

      • Hi Arthur, thanks for a swift response and good suggestion. It does the trick nicely as a workaround and I believe it is the way to go until excluding runtime endpoints with a setting in the server.xml drops from your radar and onto your desk 🙂 I’m staying tuned and certainly looking forward to seeing what you come up with.

  6. […] blog is a follow-up to our WebSphere Liberty API discovery introduction and takes you on the journey of adding Swagger support to your assets, exposing them on-premise, […]

  7. 2. Forgot one thing, which I think is kinda missing.
    a) base url: /PlayerAccount , api version: 1.0.0
    b) Grouping of contexts? (Actually haven’t tested this one yet)

    • Arthur De Magalhaes April 13, 2016

      Hey,

      (a) Because /ibm/api/docs is an aggregation of all the restful endpoints in that Liberty instance, we have logic that adds the basepath of the individual APIs into the path themselves, since likely not all APIs will share the same basepath. Same goes for the version. We have some improvements we are considering for the future, related to when you filter the docs into a specific app, by using the “root” query param (ie: /ibm/api/docs?root=/myApp)

      (b) The grouping in the UI is based on the Swagger tags used. So if you use a common tag with your resources they will be grouped together.

      • What if there are two services on the same WLP server, containing /health? That would be kinda bad?

        • Arthur De Magalhaes April 15, 2016

          Hey,

          The two services couldn’t have the same context root, by virtue of that not being allowed in a web container. But even if they contributed two swagger definitions with /health as the basepath, that’s fine because our aggregator will combine each of their basepaths with their URLs. So the two services wouldn’t have the same basepath + URL combinations.

          • Thats correct. But 2 services, with different context root can have the same api paths after the context. Such as /health
            The explorer is then exposing them as “health” and “health1” which is kinda ugly.
            I would guess we are not the only ones having an health endpoint in all of our services – therefor it would be quite awesome if the explorer would group services (contexts)!

  8. 1. Does it really need to require https/login? It would be nice if my users would not need that, it’s only used in dev and not needed at all for us.

    • Arthur De Magalhaes April 13, 2016

      Hey Johan,

      At the moment it always requires https and login. We will take this feedback into consideration for our future iterations. Thanks!

      • I second the request for a no https/login option with apidiscovery. Prototype SSL is simple, yes, production SSL is a pain, and in constant flux.

        • Arthur De Magalhaes November 21, 2016

          Hey Jim,

          I agree. Keep an eye out for the December beta driver, it might have something along those lines.

  9. Hi,

    I have this working fine for my app using (WebSphere Application Server 2016.3.0.0/wlp-1.0.12.20160305-0200). Only question is how do I ‘name’ my API for use in the explorer? It shows up as ‘default’.

    I thought that by ‘default’, it would be my context root… but I don’t see any way to influence that?

    Many thanks!

    james

  10. I try once again as my xml was escaped in a wrong way

    <server description="test server">

    <featureManager>
    <feature>apiDiscovery-1.0</feature>
    <feature>jaxrs-1.1</feature>
    <feature>jdbc-4.0</feature>
    <feature>json-1.0</feature>
    <feature>localConnector-1.0</feature>
    <feature>ejbLite-3.1</feature>
    <feature>restConnector-1.0</feature>
    <feature>servlet-3.0</feature>
    <feature>jndi-1.0</feature>
    <feature>cdi-1.0</feature>
    <feature>jpa-2.0</feature>
    <feature>ssl-1.0</feature>
    </featureManager>

    <httpEndpoint host="localhost" httpPort="9080" httpsPort="9143" id="defaultHttpEndpoint"/>

    <library id="DB2JCC4Lib">
    <fileset dir="C:\IBM\SQLLIB\java" includes="db2jcc4.jar db2jcc_license_cisuz.jar"/>
    </library>
    <dataSource id="db2" jndiName="jdbc/ebookingDS">
    <jdbcDriver libraryRef="DB2JCC4Lib"/>
    <properties.db2.jcc databaseName="DORDER" password="foobar" portNumber="50000" serverName="localhost" user="db2admin"/>
    </dataSource>
    <keyStore password="mysecret"></keyStore>
    <basicRegistry id="basic" realm="customRealm">
    <user name="adam" password="foobar" />
    </basicRegistry>

    <applicationMonitor updateTrigger="mbean"/>
    <logging consoleLogLevel="INFO" maxFileSize="20" maxFiles="10" traceFileName="trace.log" traceFormat="BASIC" traceSpecification="*=info:com.dsv.*=finest:com.ibm.ws.rsadapter.jdbc.WSJdbcConnection=finer"/>

    <webApplication id="RestArtifact" location="RestArtifact.war" name="RestArtifact"/>
    </server>

    • Arthur De Magalhaes March 02, 2016

      Hi Adam. It looks like you’re using Liberty 8558, which doesn’t support API discovery from annotations. That support is in the current Beta, https://developer.ibm.com/wasdev/downloads/liberty-profile-beta.

      Can you download the Beta and give it another try?

      Thanks.

      • Hi Arthur,
        downloading beta that helps 🙂

        Now I have another issue:
        io.swagger.models.SwaggerException: CWWKO1204E: Can not have multiple operations with the same operation ID: create

        This is not a surprise as operationId is created based on method name and my application contains many webservices so the method name is not unique. Could you fix that or report that issue to the right people.

        BR,
        Adam

        • Arthur De Magalhaes March 03, 2016

          Hey Adam,

          The operation ID must be unique within your web module, which can be achieved by choosing unique method names for your JAXRS methods, or by using the ApiOperation annotation (http://docs.swagger.io/swagger-core/current/apidocs/index.html?io/swagger/annotations/ApiOperation.html), with its nickname attribute.

          Thanks.

          • Hi Arthur,
            Thanks for the hint with @ApiOperation.nickname. Don’t you think however that it is a bit awkward to expect methods name to be globally unique? Using fully qualified name instead would be more justified in my humble opinion.

            Regards,
            Adam

            • Arthur De Magalhaes March 03, 2016

              I agree, that’s a good point. I will take this feedback into consideration for our current set of improvements to this feature. Thanks again for your input!

  11. Hi Arthur,
    I am trying to configure that but my api is not discovered. Could you please advice what am I doing wrong.

    C:\Program-extras\wlp-webProfile7-8.5.5.8\wlp\bin>productInfo version
    Product name: WebSphere Application Server
    Product version: 8.5.5.8
    Product edition: BASE_ILAN

    server.xml:

    apiDiscovery-1.0
    jaxrs-1.1
    jdbc-4.0
    json-1.0
    localConnector-1.0
    ejbLite-3.1
    restConnector-1.0
    servlet-3.0
    jndi-1.0
    cdi-1.0
    jpa-2.0
    ssl-1.0

    I use @Path annotation in my Webservices.

Join The Discussion

Your email address will not be published. Required fields are marked *