Monday, September 12, 2016

Swagger API doc for Spring Based Webservices

When any API is created one of the major challenge is to create documentation, also once documentation is created then updating it over the period of time for any changes which are done in API.

In this blog I will be demonstrating how to create API documentation for REST webservices using Swagger tool.

Swagger is very mature API doc creation tools. It provides interactive documentation with very good ecosystem like Swagger UI, Swagger Editor.
Swagger is intelligent enough to scan through the code automatically and it generates am output which are easily readable by human and even system.

In this blog i will be showing swagger integration with Spring based rest webservices(bottom up).

Prerequisite for this blog is that you have Spring API project created and working.
  • To start first download following jar files and add them in your project.
  1. aopalliance-1.0.jar
  2. aspectjrt-1.8.6.jar
  3. aspectjweaver-1.8.6.jar
  4. classmate-1.2.0.jar
  5. guava-18.0.jar
  6. mapstruct-1.0.0.CR1.jar
  7. spring-hateoas-0.18.0.RELEASE.jar
  8. spring-plugin-core-1.2.0.RELEASE.jar
  9. spring-plugin-metadata-1.2.0.RELEASE.jar
  10. springfox-core-2.2.2.jar
  11. springfox-schema-2.2.2.jar
  12. springfox-spi-2.2.2.jar
  13. springfox-spring-web-2.2.2.jar
  14. springfox-swagger-common-2.2.2.jar
  15. springfox-swagger2-2.2.2.jar
  16. swagger-annotations-1.5.3.jar
  17. swagger-models-1.5.3.jar
  • Next will be to add Swagger Config java file, this is the file which is responsible for loading swagger config, specifying the url which needs to be scanned, basic API details.
Here is the sample code.
package com.swagger.apidoc;

import static com.google.common.base.Predicates.or;
import static springfox.documentation.builders.PathSelectors.regex;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.common.base.Predicate;

import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
 @Bean
 public Docket api() {
  return new Docket(DocumentationType.SWAGGER_2).select()
    .apis(RequestHandlerSelectors.any())
    .paths(paths())
    .build()
    .apiInfo(getApiInfo());
 }
 private ApiInfo getApiInfo() {
  ApiInfo apiInfo = new ApiInfo("Swagger Demo API details",
    "These are API is demonstration of Swagger integration with spring","1.0", "TOS", 
           "abcd@test.com","@Swagger Demo", "http://java-treat.blogspot.com");
  return apiInfo;
 }
 private Predicate paths() {
  Predicate filter  = or(regex("/api.*")); // apiurl which starts with /api will be scanned by swagger.
  return filter;
 }
}

  • Above code will scan through following controller class present in the project.
package com.swagger.controller;

import java.io.IOException;

import org.apache.http.client.ClientProtocolException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.swagger.bean.Response;
import com.swagger.exception.CustomTwitterException;
import com.swagger.service.PostService;

import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthExpectationFailedException;
import oauth.signpost.exception.OAuthMessageSignerException;

@RequestMapping(value="/api")
@Controller
public class ApiController {

 private static final Logger LOGGER = LoggerFactory.getLogger(ApiController.class);

 @Autowired
 PostService demoService;

 @RequestMapping(value = "/demo/{clientId}", method = RequestMethod.GET)
 public @ResponseBody
 ResponseEntity demoMethod(@PathVariable String clientId) throws OAuthMessageSignerException,
   OAuthExpectationFailedException, OAuthCommunicationException, ClientProtocolException, IOException,
   CustomTwitterException {
  LOGGER.debug("START: ----- demoMethod [GET] method");
  ResponseEntity entity = null;
  Response resp = null;
  if (!StringUtils.isEmpty(clientId)) {
   resp = demoService.postMessageSelf(clientId);
   entity = new ResponseEntity(resp, resp.getStatus());
  } else {
   resp = new Response();
   resp.setCode("ERR404");
   resp.setMessage("System Error occurred: Invalid parameter passed, correct 
                                         the input parameter and retry");
   resp.setDeveloperMessage("System Error occurred: Invalid parameter passed, 
                                         correct the input parameter and retry");
   resp.setStatus(HttpStatus.UNAUTHORIZED);
   resp.setProcessedCount("0");
   resp.setReceivedCount("0");
   entity = new ResponseEntity(resp, resp.getStatus());
   LOGGER.debug(
   "postMessage method: Invalid parameter is passed during posting message operation,
                         throwing back error to caller {} ",
    entity.toString());
  }
  LOGGER.debug("END: ----- demoMethod [GET] method");
  return entity;
 }
 @RequestMapping(value = "/test", method = RequestMethod.GET)
 public ModelAndView demoMethod1(@PathVariable String clientId) {
  ModelAndView mdv=new ModelAndView();
  mdv.setViewName("ppTesting");
  return mdv;
 }
}
  • I have custom response class, sample for same is given below.

package com.swagger.bean;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlRootElement;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@XmlRootElement
@JsonIgnoreProperties(value={"throwable"})
public class Response implements Serializable{
 String message;
 String code;
 String receivedCount;
 String processedCount;
 public Response(){
  this.code = null;
  this.message = null;
  this.receivedCount=null;
  this.processedCount=null;
 }
 public String getMessage() {
  return message;
 }
 public void setMessage(String message) {
  this.message = message;
 }
 public String getCode() {
  return code;
 }
 public void setCode(String code) {
  this.code = code;
 }
 public String getReceivedCount() {
  return receivedCount;
 }
 public void setReceivedCount(String receivedCount) {
  this.receivedCount = receivedCount;
 }
 public String getProcessedCount() {
  return processedCount;
 }
 public void setProcessedCount(String processedCount) {
  this.processedCount = processedCount;
 }
}
  • Once above step has been completed, next start the server. Swagger API will scan the packages and it will generate the necessary json documentation. 
  • This json documentation can be parsed and documentation can be generated. In next blog i will show how to use Swagger provided UI, which does the parsing of the json output and displays in nice look and feel UI.
  • To access the generated json file, access following url, and you should see something as shown below.
  • URL: http://<hostname>:<port>/SpringSwaggerDemo/v2/api-docs
  • For my demo context root of the application was "SpringSwaggerDemo", 
  • Below is the sample json output file.

In future blogs I will show different annotations which are available which can be used for more customized documentation and also configure Swagger with Jersey based api projects, using and configuring Swagger UI.

No comments:

Post a Comment

Components of Big Data - Hadoop System

In this blog i will explain important components which are part of Hadoop System. I will give very brief overview of these components. Be...