{"id":13942,"date":"2015-05-08T15:38:45","date_gmt":"2015-05-08T13:38:45","guid":{"rendered":"https:\/\/blog.trifork.com\/?p=13942"},"modified":"2015-05-08T15:38:45","modified_gmt":"2015-05-08T13:38:45","slug":"documenting-your-rest-apis","status":"publish","type":"post","link":"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/","title":{"rendered":"Documenting your REST APIs"},"content":{"rendered":"<p>Whenever you deliver some API that is to be consumed by another party, you will get the inevitable question of providing documentation. Probably\u00a0every developer&#8217;s least favorite task.<\/p>\n<p>In Java there is javadoc, but that doesn&#8217;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&#8230; So what then? That is a question with multiple answers. In the last few\u00a0years there have been three different open-source projects that have tried to give an answer to this: <a href=\"http:\/\/swagger.io\" target=\"_blank\" rel=\"noopener\">swagger<\/a>, <a href=\"http:\/\/raml.org\/\" target=\"_blank\" rel=\"noopener\">RAML<\/a>\u00a0and <a href=\"https:\/\/apiblueprint.org\/\" target=\"_blank\" rel=\"noopener\">API BluePrint<\/a>. Of those Swagger has been around the longest and arguably gained the largest following.<\/p>\n<p>Based on the completely subjective criteria &#8216;it needs to support Java&#8217;, &#8216;what about Spring MVC?&#8217; and &#8216;can you deliver it to the customer by Monday?&#8217; 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.<\/p>\n<p><!--more--><\/p>\n<h3>Swagger 2.0?<\/h3>\n<p>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 <a href=\"http:\/\/springfox.github.io\/springfox\/\" target=\"_blank\" rel=\"noopener\">springfox<\/a>\u00a0seemed to be both still active and have Swagger 2.0 support.<\/p>\n<p>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 <a href=\"https:\/\/bintray.com\/bintray\/jcenter\" target=\"_blank\" rel=\"noopener\">JCenter<\/a> seems to be the place for those these days),<\/p>\n<blockquote>\n<pre>&lt;dependency&gt;\n    &lt;groupId&gt;io.springfox&lt;\/groupId&gt;\n    &lt;artifactId&gt;springfox-swagger2&lt;\/artifactId&gt;\n    &lt;version&gt;2.0.0-EARLYACCESS&lt;\/version&gt;\n&lt;\/dependency&gt;\n&lt;dependency&gt;\n    &lt;groupId&gt;io.springfox&lt;\/groupId&gt;\n    &lt;artifactId&gt;springfox-spring-web&lt;\/artifactId&gt;\n    &lt;version&gt;2.0.0-EARLYACCESS&lt;\/version&gt;\n&lt;\/dependency&gt;<\/pre>\n<\/blockquote>\n<p>spring configuration in both XML<\/p>\n<blockquote>\n<pre>&lt;context:annotation-config\/&gt;\n&lt;bean id=\"swagger2Config\" class=\"springfox.documentation.swagger2.configuration.Swagger2DocumentationConfiguration\"\/&gt;\n&lt;bean id=\"springConfig\" class=\"com.example.SpringConfig\"\/&gt;<\/pre>\n<pre>&lt;context:component-scan base-package=\"com.example.controllers\"\/&gt;<\/pre>\n<\/blockquote>\n<p>and Java,<\/p>\n<blockquote>\n<pre>@Configuration\n@EnableSwagger2\npublic class SpringConfig extends WebMvcConfigurerAdapter {\n\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(WEB_JAR_RESOURCE_PATTERNS)\n                .addResourceLocations(WEB_JAR_RESOURCE_LOCATION).setCachePeriod(0);\n    }\n\n    @Bean\n    public InternalResourceViewResolver getInternalResourceViewResolver() {\n        InternalResourceViewResolver resolver = new InternalResourceViewResolver();\n        resolver.setPrefix(WEB_JAR_VIEW_RESOLVER_PREFIX);\n        resolver.setSuffix(WEB_JAR_VIEW_RESOLVER_SUFFIX);\n        return resolver;\n    }\n\n    @Override\n    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {\n        configurer.enable();\n    }\n}<\/pre>\n<\/blockquote>\n<p>and why oh why my xml-based spring configuration was clashing with the Java-based configuration of the spring fox libraries&#8230;. In the end I found that the Swagger2DocumentationConfiguration bean brings in a class with the <em>@EnableWebMvc<\/em> annotation and that one doesn&#8217;t work very well when you have xml configuration using a <em>&lt;mvc:annotation-driven&gt;<\/em> section. Moving the latter to Java config got me to a working \/v2\/api-docs end point.<\/p>\n<p>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<\/p>\n<blockquote>\n<pre>&lt;dependency&gt;\n    &lt;groupId&gt;org.ajar&lt;\/groupId&gt;\n    &lt;artifactId&gt;swagger-spring-mvc-ui&lt;\/artifactId&gt;\n    &lt;version&gt;0.4&lt;\/version&gt;\n&lt;\/dependency&gt;<\/pre>\n<\/blockquote>\n<p>At this point I hit the fact that the migration to Swagger 2.0 wasn&#8217;t complete yet for all of the components in the ecosystem. Whether it was in Swagger UI or in springfox I couldn&#8217;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.<\/p>\n<p>For those now wondering if there is still a happy end to this story, stick with me a little longer.<\/p>\n<h3>Swagger 1.2<\/h3>\n<p>After a while trying several combinations of libraries and configuration, I gave in to the &#8216;can you deliver it to the customer by Monday&#8217; 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\u00a0<em>io.springfox<\/em> groupdId to the following:<\/p>\n<blockquote>\n<pre>&lt;dependency&gt;\n    &lt;groupId&gt;com.mangofactory&lt;\/groupId&gt;\n    &lt;artifactId&gt;swagger-springmvc&lt;\/artifactId&gt;\n    &lt;version&gt;1.0.2&lt;\/version&gt;\n&lt;\/dependency&gt;<\/pre>\n<\/blockquote>\n<p>and make some minor adjustments to my earlier configuration:<\/p>\n<blockquote>\n<pre>@Configuration\n@EnableSwagger\npublic class SwaggerSpringConfig extends WebMvcConfigurerAdapter {\n\n    @Autowired\n    private SpringSwaggerConfig swaggerConfig;\n\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(WEB_JAR_RESOURCE_PATTERNS)\n                .addResourceLocations(WEB_JAR_RESOURCE_LOCATION).setCachePeriod(0);\n    }\n\n    @Bean\n    public InternalResourceViewResolver getInternalResourceViewResolver() {\n        InternalResourceViewResolver resolver = new InternalResourceViewResolver();\n        resolver.setPrefix(WEB_JAR_VIEW_RESOLVER_PREFIX);\n        resolver.setSuffix(WEB_JAR_VIEW_RESOLVER_SUFFIX);\n        return resolver;\n    }\n\n    @Override\n    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {\n        configurer.enable();\n    }\n\n    @Bean\n    public SwaggerSpringMvcPlugin swaggerSpringMvcPlugin() {\n        return new SwaggerSpringMvcPlugin(swaggerConfig)\n                .directModelSubstitute(DateTime.class, String.class);\n    }\n}<\/pre>\n<\/blockquote>\n<p>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 <em>http:\/\/localhost:8080\/sdoc.jsp<\/em>. And without any changes\u00a0to my actual code.<\/p>\n<h3>Customising the api-docs<\/h3>\n<p>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:<\/p>\n<blockquote>\n<pre>@Bean\npublic SwaggerSpringMvcPlugin swaggerSpringMvcPlugin() {\n    ApiInfo apiInfo = new ApiInfoBuilder().title(\"My custom title\")\n                                          .description(\"The custom description for my REST API\")\n                                          .build();\n    return new SwaggerSpringMvcPlugin(swaggerConfig)\n            .directModelSubstitute(DateTime.class, String.class)\n            .apiInfo(apiInfo)\n            .apiVersion(\"2.0\");\n}<\/pre>\n<\/blockquote>\n<p>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.<\/p>\n<h3>What&#8217;s next?<\/h3>\n<p>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.<\/p>\n<p>Beyond that I&#8217;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.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Whenever you deliver some API that is to be consumed by another party, you will get the inevitable question of providing documentation. Probably\u00a0every developer&#8217;s least favorite task. In Java there is javadoc, but that doesn&#8217;t cut it if you are delivering a Web Service API. In that realm we already know WSDL for SOAP based [&hellip;]<\/p>\n","protected":false},"author":112,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":""},"categories":[337,31,10,94],"tags":[],"class_list":["post-13942","post","type-post","status-publish","format-standard","hentry","category-from-the-trenches","category-java","category-development","category-spring"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Documenting your REST APIs - Trifork Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Documenting your REST APIs - Trifork Blog\" \/>\n<meta property=\"og:description\" content=\"Whenever you deliver some API that is to be consumed by another party, you will get the inevitable question of providing documentation. Probably\u00a0every developer&#8217;s least favorite task. In Java there is javadoc, but that doesn&#8217;t cut it if you are delivering a Web Service API. In that realm we already know WSDL for SOAP based [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/\" \/>\n<meta property=\"og:site_name\" content=\"Trifork Blog\" \/>\n<meta property=\"article:published_time\" content=\"2015-05-08T13:38:45+00:00\" \/>\n<meta name=\"author\" content=\"Thomas Zeeman\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Thomas Zeeman\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/\",\"url\":\"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/\",\"name\":\"Documenting your REST APIs - Trifork Blog\",\"isPartOf\":{\"@id\":\"https:\/\/trifork.nl\/blog\/#website\"},\"datePublished\":\"2015-05-08T13:38:45+00:00\",\"author\":{\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/efdddc5a3544e58b3f0b5c9e4d538380\"},\"breadcrumb\":{\"@id\":\"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/trifork.nl\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Documenting your REST APIs\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/trifork.nl\/blog\/#website\",\"url\":\"https:\/\/trifork.nl\/blog\/\",\"name\":\"Trifork Blog\",\"description\":\"Keep updated on the technical solutions Trifork is working on!\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/trifork.nl\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/efdddc5a3544e58b3f0b5c9e4d538380\",\"name\":\"Thomas Zeeman\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/7d4352b454b0123a6a8e1b71a69bd5de?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/7d4352b454b0123a6a8e1b71a69bd5de?s=96&d=mm&r=g\",\"caption\":\"Thomas Zeeman\"},\"url\":\"https:\/\/trifork.nl\/blog\/author\/thomasz\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Documenting your REST APIs - Trifork Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/","og_locale":"en_US","og_type":"article","og_title":"Documenting your REST APIs - Trifork Blog","og_description":"Whenever you deliver some API that is to be consumed by another party, you will get the inevitable question of providing documentation. Probably\u00a0every developer&#8217;s least favorite task. In Java there is javadoc, but that doesn&#8217;t cut it if you are delivering a Web Service API. In that realm we already know WSDL for SOAP based [&hellip;]","og_url":"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/","og_site_name":"Trifork Blog","article_published_time":"2015-05-08T13:38:45+00:00","author":"Thomas Zeeman","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Thomas Zeeman","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/","url":"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/","name":"Documenting your REST APIs - Trifork Blog","isPartOf":{"@id":"https:\/\/trifork.nl\/blog\/#website"},"datePublished":"2015-05-08T13:38:45+00:00","author":{"@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/efdddc5a3544e58b3f0b5c9e4d538380"},"breadcrumb":{"@id":"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/trifork.nl\/blog\/documenting-your-rest-apis\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/trifork.nl\/blog\/"},{"@type":"ListItem","position":2,"name":"Documenting your REST APIs"}]},{"@type":"WebSite","@id":"https:\/\/trifork.nl\/blog\/#website","url":"https:\/\/trifork.nl\/blog\/","name":"Trifork Blog","description":"Keep updated on the technical solutions Trifork is working on!","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/trifork.nl\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/efdddc5a3544e58b3f0b5c9e4d538380","name":"Thomas Zeeman","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/7d4352b454b0123a6a8e1b71a69bd5de?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/7d4352b454b0123a6a8e1b71a69bd5de?s=96&d=mm&r=g","caption":"Thomas Zeeman"},"url":"https:\/\/trifork.nl\/blog\/author\/thomasz\/"}]}},"_links":{"self":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts\/13942","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/users\/112"}],"replies":[{"embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/comments?post=13942"}],"version-history":[{"count":0,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts\/13942\/revisions"}],"wp:attachment":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/media?parent=13942"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/categories?post=13942"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/tags?post=13942"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}