Trifork Blog

Axon Framework, DDD, Microservices

Documenting your REST APIs

May 8th, 2015 by
|

Whenever you deliver some API that is to be consumed by another party, you will get the inevitable question of providing documentation. Probably every developer’s least favorite task.

In Java there is javadoc, but that doesn’t cut it if you are delivering a Web Service API. In that realm we already know WSDL for SOAP based Web Services. Then again, every developer seems to prefer REST based Web Services these days and those are not WSDL based… So what then? That is a question with multiple answers. In the last few years there have been three different open-source projects that have tried to give an answer to this: swagger, RAML and API BluePrint. Of those Swagger has been around the longest and arguably gained the largest following.

Based on the completely subjective criteria ‘it needs to support Java’, ‘what about Spring MVC?’ and ‘can you deliver it to the customer by Monday?’ I decided to take a stab at documenting an existing API using Swagger. It is written in something that can run on a JVM, has Spring MVC support (via third party libraries) and seemed to be the easiest to set up based on their examples and various other online resources.

Swagger 2.0?

First things first. Like everyone else I took a look at the documentation (you do that too right? right???) and found that Swagger 2.0 had been out for some time and seemed to address various complaints about version 1 in comparison with the other two projects. Of the libraries that offered Spring integration the one called springfox seemed to be both still active and have Swagger 2.0 support.

Next I started to embark on a tour of the examples and tried to get everything to work. Most of it was figuring out the right maven dependencies (for some reason JCenter seems to be the place for those these days),

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.0.0-EARLYACCESS</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-spring-web</artifactId>
    <version>2.0.0-EARLYACCESS</version>
</dependency>

spring configuration in both XML

<context:annotation-config/>
<bean id="swagger2Config" class="springfox.documentation.swagger2.configuration.Swagger2DocumentationConfiguration"/>
<bean id="springConfig" class="com.example.SpringConfig"/>
<context:component-scan base-package="com.example.controllers"/>

and Java,

@Configuration
@EnableSwagger2
public class SpringConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(WEB_JAR_RESOURCE_PATTERNS)
                .addResourceLocations(WEB_JAR_RESOURCE_LOCATION).setCachePeriod(0);
    }

    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix(WEB_JAR_VIEW_RESOLVER_PREFIX);
        resolver.setSuffix(WEB_JAR_VIEW_RESOLVER_SUFFIX);
        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

and why oh why my xml-based spring configuration was clashing with the Java-based configuration of the spring fox libraries…. In the end I found that the Swagger2DocumentationConfiguration bean brings in a class with the @EnableWebMvc annotation and that one doesn’t work very well when you have xml configuration using a <mvc:annotation-driven> section. Moving the latter to Java config got me to a working /v2/api-docs end point.

Then came the task to get it all to work nicely. For that I wanted to get the Swagger UI to work as well. According to the examples I should be able to get it to work with adding yet another dependency

<dependency>
    <groupId>org.ajar</groupId>
    <artifactId>swagger-spring-mvc-ui</artifactId>
    <version>0.4</version>
</dependency>

At this point I hit the fact that the migration to Swagger 2.0 wasn’t complete yet for all of the components in the ecosystem. Whether it was in Swagger UI or in springfox I couldn’t figure out, but in the end I kept getting issues where the JavaScript library kept complaining about getting an outdated version of the api-docs format after which it would crash on an undefined property.

For those now wondering if there is still a happy end to this story, stick with me a little longer.

Swagger 1.2

After a while trying several combinations of libraries and configuration, I gave in to the ‘can you deliver it to the customer by Monday’ requirement and took the pragmatic approach and used the Swagger 1.2 versions of all the components. This meant I had to change the maven dependencies for the io.springfox groupdId to the following:

<dependency>
    <groupId>com.mangofactory</groupId>
    <artifactId>swagger-springmvc</artifactId>
    <version>1.0.2</version>
</dependency>

and make some minor adjustments to my earlier configuration:

@Configuration
@EnableSwagger
public class SwaggerSpringConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private SpringSwaggerConfig swaggerConfig;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(WEB_JAR_RESOURCE_PATTERNS)
                .addResourceLocations(WEB_JAR_RESOURCE_LOCATION).setCachePeriod(0);
    }

    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix(WEB_JAR_VIEW_RESOLVER_PREFIX);
        resolver.setSuffix(WEB_JAR_VIEW_RESOLVER_SUFFIX);
        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Bean
    public SwaggerSpringMvcPlugin swaggerSpringMvcPlugin() {
        return new SwaggerSpringMvcPlugin(swaggerConfig)
                .directModelSubstitute(DateTime.class, String.class);
    }
}

and all of a sudden I had a working api-docs endpoint as well as a, more or less, working Swagger UI page at the url http://localhost:8080/sdoc.jsp. And without any changes to my actual code.

Customising the api-docs

The API documentation so far is using a number of place holders for the title, description, version and some other properties. To fix that all we have to do is make some minor changes to the spring configuration:

@Bean
public SwaggerSpringMvcPlugin swaggerSpringMvcPlugin() {
    ApiInfo apiInfo = new ApiInfoBuilder().title("My custom title")
                                          .description("The custom description for my REST API")
                                          .build();
    return new SwaggerSpringMvcPlugin(swaggerConfig)
            .directModelSubstitute(DateTime.class, String.class)
            .apiInfo(apiInfo)
            .apiVersion("2.0");
}

Further adjustments to the methods and their payload, both request and response, are a bit more invasive and require some Swagger annotations (all conveniently prefixed with Api for some reason) to be placed on the class, method or property that needs a bit of moulding.

What’s next?

We now have a documented REST API, which is better than nothing I would say, and at a minimum of effort at that. It will also automatically update as it is using the actual implementation to generate the documentation, a nice bonus! So lets use it and see where we find something we could improve upon.

Beyond that I’m also interested to see what happens if we take the other way round and start with the API specification, generate the interface classes from that and then implement it.

12 Responses

  1. May 21, 2015 at 22:07 by Albert van 't Hart

    Thanks for sharing!

    Another new interesting project is Spring REST docs when you are building webservices using Spring (Boot).

    We are already using it several projects, see:
    https://github.com/spring-projects/spring-restdocs

  2. May 22, 2015 at 16:05 by Joris Kuipers

    Note that the Spring team is working on a REST documentation project as an alternative to Swagger as well: check out https://github.com/spring-projects/spring-restdocs if you’re interested (there’s links there to slides and a video).

  3. June 10, 2015 at 16:34 by Renault Hess

    Hi, I followed your tutorial, but still can’t get even the Swagger 1.2 to work. Care to assist please?

    Tx

  4. June 11, 2015 at 14:30 by Renault Hess

    Hi, nevermind, I got it working , thatnks.

  5. June 11, 2015 at 14:37 by Tom DeBruycker

    Thanks for the article. I have gone down the same path trying almost every combination of jars to get a 2.0 Swagger version to run. I have not found a sample project which gives the complete pom.xml to show all jar dependencies.

    Were you ever able to get the 2.0 version to run? If so, would you publish your pom.xml?

    • June 11, 2015 at 17:26 by Thomas Zeeman

      I managed to get the 2.0-EARLYACCESS to respond to the /v2/api-docs end point but I wasn’t able to get the Swagger-UI to work with that one.

      The two dependencies above were all I had to add beyond the standard spring dependencies. Do be aware that I could only get the 2.0.0-EARLYACCESS version out of the JCenter repository. No final or SNAPSHOT release from JCenter and nothing at all from Maven Central.

  6. June 11, 2015 at 17:04 by Thomas Zeeman

    @Albert & Joris: Thanks for sharing. Looks interesting.
    At the moment not an option yet, since the project I was working on isn’t on Spring 4.1 yet.

  7. June 11, 2015 at 17:07 by Thomas Zeeman

    @Renault: Good to hear you managed to get it working. Anything missing from the steps I provided?

  8. June 18, 2015 at 16:14 by mandar

    hi, i have submitted my concern related to the blog post on stackoverflow , request you to please look into it and help me .
    http://stackoverflow.com/questions/30917831/swagger-2-0-3-with-spring-mvc-throws-httpmediatypenotacceptableexception-could

    • June 22, 2015 at 15:36 by Thomas Zeeman

      Thanks for the feedback. I noticed they’ve now delivered a final for SpringFox 2.0 and made it available on Maven Central again.

      The HttpMedia exption is not something I experienced during my experimentation that led to this blog. I did see soem related Q&As on StackOverflow. See my answer there.

  9. August 11, 2015 at 11:41 by Issam

    Please read the official springfox documentation. All the blocking points in your article seem to have an answer here : http://springfox.github.io/springfox/docs/current/#introduction

    • August 13, 2015 at 14:04 by Thomas Zeeman

      Thanks for the heads up on that. I’ll try to have another go at the 2.0 release soon.