Swagger
Springfox supports both version 1.2 and version 2.0 of the Swagger specification. Where possible, the Swagger 2.0 specification is preferable.
The swagger-core annotations, as provided by swagger-core, are typically used to decorate the java source code of an API which is bing 'swaggered'. Springfox is aware of the Swagger-Core Annotations and will favor those annotations over inferred defaults.
Swagger 1.2 vs Swagger 2.0
One major difference between the two swagger specification is the composition of the generated swagger documentation.
With Swagger 1.2 an applications API is represented as a Resource Listing and multiple API Declarations which has the
implication of producing multiple JSON files
With Swagger 2.0 things are much simpler and an application’s API can be represented in a single JSON file.
Moving from swagger-springmvc?
Here is a guide to help with the transition from 1.0.2 to 2.0.
Legacy documentation is available here.
Springfox configuration and demo applications
The springfox-demos repository contains a number of sample Spring application which can be used a reference.
Configuring Springfox
To enable support for swagger specification 1.2 use the annotation@EnableSwagger
To enable support for swagger specification 2.0 use the annotation@EnableSwagger2
To document the service we use a . This is changed to be more inline with the fact that expressing the
contents of the documentation is agnostic of the format the documentation is rendered.Docket
Docket stands for A summary or other brief statement of the contents of a document; an abstract.
Docket helps configure a subset of the services to be documented and groups them by name. Significant changes
to this is the ability to provide an expressive predicate based for api selection.
import static springfox.documentation.builders.PathSelectors.*;
import static com.google.common.base.Predicates.*;
@Bean
public Docket swaggerSpringMvcPlugin() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("business-api")
.select()
//Ignores controllers annotated with @CustomIgnore
.apis(not(withClassAnnotation(CustomIgnore.class)) //Selection by RequestHandler
.paths(paths()) // and by paths
.build()
.apiInfo(apiInfo())
.securitySchemes(securitySchemes())
.securityContext(securityContext());
}
//Here is an example where we select any api that matches one of these paths
private Predicate<String> paths() {
return or(
regex("/business.*"),
regex("/some.*"),
regex("/contacts.*"),
regex("/pet.*"),
regex("/springsRestController.*"),
regex("/test.*"));
}
For a list of handy predicates Look at RequestHandlerSelectors and PathSelectors.
Configuring the ObjectMapper
A simple way to configure the object mapper is to listen for the event. Regardless of
whether there is a customized ObjectMapper in play with a corresponding MappingJackson2HttpMessageConverter, the
library always has a configured ObjectMapper that is customized to serialize swagger 1.2 and swagger 2.0 types.ObjectMapperConfigured
In order to do this implement the interface. The event has a handle
to the ObjectMapper that was configured. Configuring application specific ObjectMapper customizations in this
applicaiton event handler guarantees that application specific customizations will be applied to each and every
ObjectMapper that is in play.ApplicationListener<ObjectMapperConfigured>
If you encounter a NullPointerException during application startup like this issue. Its because most likely the isn’t working.
These adapter especially in a non-spring-boot scenarios will only get loaded if the @EnableWebMvc
annotation is present.WebMvcConfigurerAdapter
Caveat to using the library is that it depends on Jackson for serialization, more importantly the ObjectMapper. A
good example of where this breaks down is the following issue when using Gson serialization
Customizing the swagger endpoints.
By default the swagger service descriptions are generated at the following urls
| Swagger version | Documentation Url | Group |
|---|---|---|
2.0 |
/v2/api-docs?group=external |
external group via docket.groupName() |
1.2 |
/api-docs |
implicit default group |
2.0 |
/api-docs?group=external |
external group via docket.groupName() |
2.0 |
/v2/api-docs |
implicit default group |
To customize these endpoints, loading a property source with the following properties allows the properties to be overridden
| Swagger version | Override property |
|---|---|
2.0 |
springfox.documentation.swagger.v2.path |
1.2 |
springfox.documentation.swagger.v1.path |
Overriding property datatypes
Using the we can override the inferred data types. However it is restricted
to only allow data types to be specified with a fully qualified class name. For e.g. if we have the following
definitionApiModelProperty#dataType
// if com.qualified.ReplaceWith is not a Class that can be created using Class.forName(...)
// Original will be replaced with the new class
@ApiModelProperty(dataType = "com.qualified.ReplacedWith")
public Original getOriginal() { ... }
// if ReplaceWith is not a Class that can be created using Class.forName(...) Original will be preserved
@ApiModelProperty(dataType = "ReplaceWith")
public Original getAnotherOriginal() { ... }
Docket XML Configuration
To use the plugin you must create a spring java configuration class which uses spring’s @Configuration.
This config class must then be defined in your xml application context.
<!-- Required so springfox can access spring's RequestMappingHandlerMapping -->
<mvc:annotation-driven/>
<bean class="com.yourapp.configuration.MySwaggerConfig"/>
@Configuration
@EnableSwagger //Loads the spring beans required by the framework
public class MySwaggerConfig {
/**
* Every Docket bean is picked up by the swagger-mvc framework - allowing for multiple
* swagger groups i.e. same code base multiple swagger resource listings.
*/
@Bean
public Docket customDocket(){
return new Docket(); //some customization goes here
}
}
Docket Spring Java Configuration
-
Use the
@EnableSwaggeror@EnableSwagger2annotation. -
Define one or more Docket instances using springs
@Beanannotation.
@Configuration
@EnableWebMvc //NOTE: Only needed in a non-springboot application
@EnableSwagger2
@ComponentScan("com.myapp.controllers")
public class CustomJavaPluginConfig {
@Bean //Don't forget the @Bean annotation
public Docket customImplementation(){
return new Docket()
.apiInfo(apiInfo())
.includePatterns(".*pet.*");
}
//...
}
Swagger group
A swagger group is a concept introduced by this library which is simply a unique identifier for a Swagger Resource Listing within your application. The reason this concept was introduced was to support applications which require more than one Resource Listing. Why would you need more than one Resource Listing? - A single Spring Web MVC application serves more than one API e.g. publicly facing and internally facing. - A single Spring Web MVC application serves multiple versions of the same API. e.g. v1 and v2
In most cases an application will not need more than one Resource Listing and the concept of swagger groups can be ignored.
Configuring the output of operationId in a Swagger 2.0 spec
As defined operationId was
introduced in the Swagger 2.0 spec, the operationId parameter, which was referred to as nickname in pre-2.0
versions of the Swagger spec, provides the author a means by which to describe an API operation with a friendly name
. This field is often used by consumers of a Swagger 2.0 spec in order to name functions in generated clients. An
example of this can be seen in the swagger-codegen project.
The default value of operationId according to Springfox
By default, when using Springfox in Swagger 2.0 mode, the value of operationID will be rendered using the
following structure: “[java_method_name_here]Using[HTTP_verb_here]”. For example, if one has a method getPets()
connected to an HTTP GET verb, Springfox will render getPetsUsingGET for the operationId.
Given this annotated method …
@ApiOperation(value = "")
@RequestMapping(value = "/pets", method = RequestMethod.GET)
public Model getAllThePets() {
...
}
the default operationId will render looking like this:
"paths": {
"/pets": {
"get": {
...
"operationId":"getAllThePetsUsingGET"
...
}
}
}
Customizing the value of operationId
In the event you wish to overide the default operationId which Springfox renders, you may do so by providing the
nickname element in an @ApiOperation annotation.
Given this annotated method …
@ApiOperation(value = "", nickname = "getMeAllThePetsPlease")
@RequestMapping(value = "/pets", method = RequestMethod.GET)
public Model getAllThePets() {
...
}
… the customized operationId will render looking like this:
"paths": {
"/pets": {
"get": {
...
"operationId":"getMeAllThePetsPlease"
...
}
}
}
Changing how Generic Types are Named
By default, types with generics will be labeled with '\u00ab'(<<), '\u00bb'(>>), and commas. This can be problematic
with things like swagger-codegen. You can override this behavior by implementing your own GenericTypeNamingStrategy.
For example, if you wanted List<String> to be encoded as 'ListOfString' and Map<String, Object>
to be encoded as 'MapOfStringAndObject' you could implement the following:
then during plugin customization:
docket.forCodeGeneration(true|false);
Extensibility
The library provides a variety of extensibility hooks to enrich/ augment the schema and service models
-
For enriching models and properties (TODO)
-
For enriching services models (TODO)
Example application
For an examples for spring-boot, vanilla spring applications take a look examples in the demo application.
Configuring springfox-staticdocs
Springfox-staticdocs is a module which brings together springfox and swagger2markup. Swagger2Markup is a library which simplifies the generation of an up-to-date RESTful API documentation by combining documentation that’s been hand-written with auto-generated API documentation produced by Springfox. The result is intended to be an up-to-date, easy-to-read, on- and offline user guide. Swagger2Markup converts a Swagger JSON or YAML file into several AsciiDoc or GitHub Flavored Markdown documents which can be converted to HTML, PDF and EPUB. The output of Swagger2Markup can be used as an alternative to swagger-ui and can be served as static content.
Usage guide
Adding springfox-staticdocs to your project
Maven
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-staticdocs</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
Gradle
dependencies {
...
compile 'io.springfox:springfox-swagger2:2.0.0'
testCompile 'io.springfox:springfox-staticdocs:2.0.0'
...
}
Generate Markup during an unit test
Spring’s MVC Test framework can be used to make a request to a springfox Swagger endpoint during an unit test. The ResultHandler Swagger2MarkupResultHandler can be used to convert the Swagger JSON response into an AsciiDoc document. The custom ResultHandler is part of springfox-staticdocs. That way you also verify that your Swagger endpoint is working. The following is an example with Spring Boot:
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)
public class Swagger2MarkupTest {
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
@Test
public void convertSwaggerToAsciiDoc() throws Exception {
this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc/generated").build())
.andExpect(status().isOk());
}
@Test
public void convertSwaggerToMarkdown() throws Exception {
this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/markdown/generated")
.withMarkupLanguage(MarkupLanguage.MARKDOWN).build())
.andExpect(status().isOk());
}
}
If you want to combine the generated documentation with your hand-written documentation, then have a look at the user guide of swagger2Markup. You can also include generated CURL request, HTTP request and HTTP response example snippets from spring-restdocs into the generated documentation.