Product Engineering

Swagger Annotation And Spring Configuration

Swagger Annotation And Spring Configuration

In the previous blog post ‘Swagger Specification and Code Generation one-o-one’, we learned about Swagger specification and its power to speed up web application development by code generator tool swagger-codegen.

In this article, we will explore second approach of development using Swagger i.e. Bottom up approach where in services (REST Controllers) are first created and then Swagger core is used to generate definitions automatically.

To understand Swagger configuration better, let’s take an example of Spring REST application which facilitates user to book doctor’s appointment.

Steps to configure

We will use the Springfox implementation of the Swagger specification.

1.  Adding maven dependency in pom.xml

<dependency>

<groupId>io.springfox</groupId>

<artifactId>springfox-swagger2</artifactId>

<version>2.4.0</version>

</dependency>

Add below dependency to use Swagger UI

<dependency>

<groupId>io.springfox</groupId>

<artifactId>springfox-swagger-ui</artifactId>

<version>2.4.0</version>

</dependency>

2. Enable matrix variables (not required in Spring 4.1)

Add <mvc:annotation-driven enable-matrix-variables="true"/> in spring-mvc-config.xml

3. Configure Docket configuration bean

Docket class is basically a builder which is meant to be primary interface for Spring – Swagger integration

  • Docket XML Configuration:
    • To Use plugin, we should create Java configuration class with @Configuration class and define this class in application context file.
@EnableSwagger2

public class ApplicationSwaggerConfig {

@Bean

public Docket api() {

return new Docket(DocumentationType.SWAGGER_2)

.select().apis(RequestHandlerSelectors.basePackage("  com.swagger.demo"))

.paths(PathSelectors.any())

.build()

.pathMapping("/api");

}

}
  • Add <mvc:annotation-driven/> in application context file
  • Add <context:component-scan base-package=” com.swagger.demo”> in application context file
  • Docket Java Configuration:
    • Use the@EnableSwagger or @EnableSwagger2 annotation
    • Define Docket instances using springs@Bean annotation
 @EnableSwagger2

@ComponentScan("com.swagger.demo")

public class ApplicationSwaggerConfig {

@Bean

public Docket api() {

return new Docket(DocumentationType.SWAGGER_2)

.select()

.apis(RequestHandlerSelectors.basePackage(("com.swagger.demo")))

.paths(PathSelectors.any())

.build()

.pathMapping("/api");

}

}

Select() => This method returns an instance of ApiSelectorBuilder, which provides a way to control the endpoints.

RequestHandlerSelectors allows to filter the API according to the base package, class annotation, and method annotations.

PathSelectors provides additional filtering which scans the request paths of your application. You can use any(), none(), regex(), or ant().

pathMapping(java.lang.String path) => This docket class method is  to add a servlet path mapping

4. Enable Swagger UI

XML configuration:

<mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources/"/>

<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>

Java Configuration:

You must create a class that extends WebMvcConfigurerAdapter, and is annotated with @EnableWebMvc and add below method

@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(“swagger-ui.html”) .addResourceLocations(“classpath:/META-INF/resources/”); registry.addResourceHandler(“/webjars/**”) .addResourceLocations(“classpath:/META-INF/resources/webjars/”); }

5. Testing URL

Swagger endpoints can be accessed at

  • Testing Swagger API documentation

http://localhost:8080//swagger-ui.html

  • Testing Swagger UI

http://localhost:8080//v2/api-docs

Check below configuration of Doctor Appointment Booking

Code snippet of operation Id: Get AppointmentBy DoctorID

@Api(description = "Doctors Appointment Operation", value = "/appointment")

@Controller

@RequestMapping(value = "/appointments")

public class DoctorAppointmentController {

@Autowired

AppointmentServiceImpl appointmentServiceImpl ;

@ApiOperation(value = "Returns Appointment Details by Doctor Id", notes = "Returns Appointment Details Like Doctor's Name, Timing", response = ArrayList.class,

authorizations = {@Authorization(value="appointoauth",scopes = {@AuthorizationScope(scope = "get:appointments", description = "Allows Fetching Appointments")})})

@ApiResponses(value = { @ApiResponse(code = 200, message = "Sucessful Retrieval of Appointments", response = ArrayList.class ) ,

@ApiResponse(code = 404, message = "Doctor with Specified ID Does Not Exist"),

@ApiResponse(code = 500, message = "Internal server error")})

@ApiImplicitParams(value = {@ApiImplicitParam(name = "docId", value = "Doctor Id", required = true, dataType = "int", paramType = "path")})

@RequestMapping(value = "/{docId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)

@ResponseBody

public List<Slot> getAppointmentByDoctorID(@PathVariable int docId){

return appointmentServiceImpl.getAppointmentByDoctorID(docId);

}//other methods

}

Model: MovieBean

@ApiModel(value = "Slot" , description = "Prototype for booking appointment")

public class Slot {

@ApiModelProperty(value = "Slot Id" , position = 1 , required = true)

private int  slotId;

@ApiModelProperty(value = "Start Time" , position = 2 , required = true)

private String startTime;

@ApiModelProperty(value = "Appointment Date" , position = 3 , required = true)

private Date appointmentDay;

@ApiModelProperty(value = "End Time" , position = 4 , required = true)

private String endTime;

@ApiModelProperty(value = "Doctor Id" , position = 5 , required = true)

private int doctorId;

//getters and setters

}

Resource Declaration:

  • @Api => This is used to declare Swagger resource. This is class/Interface/Enum level annotation. Types annotated with @Api will be scanned by Swagger

Operation Declarations:

  • @ApiOperation => This is method level annotation. Only methods that are annotated with @ApiOperation will be scanned and added the API Declaration
  • @ApiResponses => Method level annotation and it describes a concrete possible response
  • @ApiResponse => Method level annotation and cannot be used directly on the method and needs to be included in the array value of @ApiResponses

In this case we declare that the getAppointmentByDoctorID operation uses the appointoauth authorization scheme. Then using the @AuthorizationScope we fine-tune the definition by saying it requires the get:appointments scope. You can see that @AuthorizationScope is used as an input to @Authorization.

Model Declarations:

  • @ApiModel => This is class/Interface/Enum level annotation. It describes model classes. It also supports polymorphism and inheritance through elements discriminator and subtypes.

Discriminator is a distinguishing field of top model and subtypes includes all inherited classes.

  • @ApiModelProperty => Describes model properties and allows controlling Swagger-specific definitions such as allowed values. It also offers additional filtering properties in case you want to hide the property in certain scenarios.

Documentation

We are all set to test documentation now.

When you hit documentation URL i.e. http://localhost:8080/swaggerdemo/v2/api-docs

User can view API documentation generated which is exactly the reverse of what happens in top down approach where in first specification is created and then services are generated using tool codegen. Please click here to revisit top down approach.

Below is specification generated for Doctor Booking Appointment application.

{

"swagger": "2.0",

"info": {

"description": "Api Documentation",

"version": "1.0",

"title": "Api Documentation",

"termsOfService": "urn:tos",

"contact": {},

"license": {

"name": "Apache 2.0",

"url": "http://www.apache.org/licenses/LICENSE-2.0"

}

//Paths

//Operations

//definitions

}

You can download whole specification here.

Swagger UI Testing:

You can test Swagger UI in browser by visiting http://localhost:8080/swaggerdemo/swagger-ui.html

Below are all operations listed.

swagger annotation and configuration

swagger annotation and configuration

Now you can keep on implementing services, operations and have your code and document in sync.

In the next blog of series, we will explore other exciting features of Swagger. Stay tuned!

References:

https://springfox.github.io/springfox/docs/current/#swagger

https://github.com/swagger-api