Enterprise Java

Spring Rest API with Swagger – Integration and configuration

Nowadays, exposed APIs are finally getting the attention they deserve and companies are starting to recognize their strategic value. However, working with 3rd party APIs can be really tedious work, especially when these APIs are not maintained, ill designed or missing any documentation. That’s why I decided to look around for ways to provide fellow programmers and other team members with proper documentation when it comes to integration. One way to go is to use WADL, which is a standard specifically designed to describe HTTP based web applications (like REST web services). However there are few drawback when using WADL that made me look elsewhere for solutions how to properly document and expose API documentation.
 

Swagger

Another way might be to go with Swagger. Swagger is both specification and framework implementation that supports full life cycle of RESTful web services development. The specification itself is language-agnostic, which might come in handy in heterogeneous environment. Swagger also comes with Swagger UI module which allows both programmers and other team members to meaningfully interact with APIs and gives them a way to work with it while providing access to the documentation.

Spring with Jersey example

Not long ago, I came across an article describing Swagger specification and I was pretty intrigued to give it a try. At that time I was working on a sweet little microservice so I had an ideal testing ground to try it out. Based on that I prepared a short example about how to use Swagger in your application, when you are using Spring framework and Jersey. Example code models simplified REST API for a subset of possible APIs in a shop application scenario.

Note: Import declarations were omitted from all Java code samples.

Jersey servlet

Before we get down to introducing Swagger to our code, lets take a moment and explore our example a little. First of all, lets look at web.xml. There is plain old web.xml with few simple declarations and mappings in code sample below. Nothing special here, just a bunch of configuration.

<web-app id="SpringWithSwagger" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<display-name>Spring Jersey Swagger Example</display-name>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:beans.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<servlet>
		<servlet-name>jersey-serlvet</servlet-name>
		<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
		<init-param>
			<param-name>javax.ws.rs.Application</param-name>
			<param-value>com.jakubstas.swagger.SpringWithSwagger</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>jersey-serlvet</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>
</web-app>

Endpoint

Second thing we are going to need is the endpoint that defines our REST service – for example employee endpoint for listing current employees. Once again, there is nothing extraordinary, only a few exposed methods providing core API functionality.

package com.jakubstas.swagger.rest;

@Path("/employees")
public class EmployeeEndpoint {

    private List<Employee> employees = new ArrayList<Employee>();

    {
        final Employee employee = new Employee();
        employee.setEmployeeNumber(1);
        employee.setFirstName("Jakub");
        employee.setSurname("Stas");

        employees.add(employee);
    }

    @OPTIONS
    public Response getProductsOptions() {
        final String header = HttpHeaders.ALLOW;
        final String value = Joiner.on(", ").join(RequestMethod.GET, RequestMethod.OPTIONS).toString();

        return Response.noContent().header(header, value).build();
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getEmployees() {
        return Response.ok(employees).build();
    }
}

Swagger dependencies

First thing we need to do is to include all required Swagger dependencies in our pom.xml as shown below (lucky for us it’s only a single dependency).

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	...
	<properties>
		...
		<swagger-version>1.3.8</swagger-version>
		...
	</properties>
	...
	<dependencies>	
		...
		<!-- Swagger -->
		<dependency>
			<groupId>com.wordnik</groupId>
			<artifactId>swagger-jersey2-jaxrs_2.10</artifactId>
			<version>${swagger-version}</version>
		</dependency>
		...
	</dependencies>
</project>

Swagger configuration

Now, lets take a look how Swagger integrates into our example. As with any introduction of a new dependency in your project, you should be concerned with how invasive and costly this process will be. The only effected places will be your REST endpoints, Spring configuration and some transfer objects (given you choose to include them) as you will see in following code samples. This means that there is no configuration needed in web.xml for Swagger to work with your Spring application, meaning it’s rather non-invasive in this way and remains constrained within APIs realm.

You need three basic properties for Swagger to work:

  • API version
    • Provides the version of the application API
  • base path
    • The root URL serving the API
  • resource package
    • Defines package where to look for Swagger annotations

Since API maintenance is primarily responsibility of analysts and programmers, I like to keep this configuration in a separate property file called swagger.properties. This way it is not mixed with application configuration and is less likely to be modified by accident. Following snippet depicts such a configuration file.

swagger.apiVersion=1.0
swagger.basePath=http://[hostname/ip address]:[port]/SpringWithSwagger/rest
swagger.resourcePackage=com.jakubstas.swagger.rest

For a second part of configuration I created a configuration bean making use of previously mentioned properties. Using Spring’s @PostConstruct annotation providing bean life-cycle hook, we are able to instantiate and set certain attributes that Swagger requires, but is not able to get (in current version at least).

package com.jakubstas.swagger.rest.config;

/**
 * Configuration bean to set up Swagger.
 */
@Component
public class SwaggerConfiguration {

    @Value("${swagger.resourcePackage}")
    private String resourcePackage;

    @Value("${swagger.basePath}")
    private String basePath;

    @Value("${swagger.apiVersion}")
    private String apiVersion;

    @PostConstruct
    public void init() {
        final ReflectiveJaxrsScanner scanner = new ReflectiveJaxrsScanner();
        scanner.setResourcePackage(resourcePackage);

        ScannerFactory.setScanner(scanner);
        ClassReaders.setReader(new DefaultJaxrsApiReader());

        final SwaggerConfig config = ConfigFactory.config();
        config.setApiVersion(apiVersion);
        config.setBasePath(basePath);
    }

    public String getResourcePackage() {
        return resourcePackage;
    }

    public void setResourcePackage(String resourcePackage) {
        this.resourcePackage = resourcePackage;
    }

    public String getBasePath() {
        return basePath;
    }

    public void setBasePath(String basePath) {
        this.basePath = basePath;
    }

    public String getApiVersion() {
        return apiVersion;
    }

    public void setApiVersion(String apiVersion) {
        this.apiVersion = apiVersion;
    }
}

Last step is to declare following three Swagger beans: ApiListingResourceJSON, ApiDeclarationProvider and ResourceListingProvider.

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
	<context:component-scan base-package="com.jakubstas.swagger" />
	<context:property-placeholder location="classpath:swagger.properties" />

	<bean class="com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON" />
	<bean class="com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider" />
	<bean class="com.wordnik.swagger.jaxrs.listing.ResourceListingProvider" />
</beans>

Swagger is now configured and you can check whether your setup is working properly. Just enter the URL from your basePath variable followed by /api-docs into your browser and check the result. You should see an output similar to following snippet I received after accessing http://[hostname]:[port]/SpringWithSwagger/rest/api-docs/ in my example.

{"apiVersion":"1.0","swaggerVersion":"1.2"}

What is next?

If you followed all steps you should now have working setup to start with an API documentation. I will showcase how to describe APIs using Swagger annotations in my next article called Spring Rest API with Swagger – Creating documentation. The code used in this micro series is published on GitHub and provides examples for all discussed features and tools. Please enjoy!

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Andrew
Andrew
10 years ago

The title is misleading. It should read “Jersey Rest API with Swagger – Integration and Configuration”.

ashk
ashk
9 years ago

Yes rename the title it is not spring from any angle.. You are misleading other peoples..

6 years ago

Is swagger jars are java 8 dependent. My project uses java 7 and it is getting failed in weblogic server.

Back to top button