Recently, Swagger was introduced into the project to support automatic document generation, and I found that many articles only covered how to access and how to use them. But for actual engineering practice, there is no corresponding best practice scheme. So I went through the content and documentation to put together a set of best practice guidelines.

Swagger and Springfox

Before the formal introduction, we need to understand the relationship between Swagger and Springfox. Those of you who have used Swagger in Spring projects know that Spring projects integrate Swagger functionality through Springfox.

What is the Swagger

Swagger is a series of tools for Restful API development, including:

  • OpenAPI Specification: How to describe the API of a system
  • Swagger Codegen: For generating server and client code through API specifications
  • Swagger Editor: Used to write API specifications
  • Swagger UI: Used to showcase API specifications

To put it simply, we can think of Swagger as primarily creating and implementing an API specification that describes the API interface of the system.

What is Springfox

Simply put, Springfox is a tool that generates API documents by scanning and extracting information from code. It supports swagger, RAML, jsonapi, and many other API document formats. Since we are focusing on Swagger, Springfox is a middle layer that integrates SpringMVC with Swagger to automatically scan the Controller layer’s interface to generate description data (JSON format) that complies with the Swagger API specification.

Through Springfox, swagger can be integrated with SpringBoot project, there are a lot of online integration articles, here is no longer described, specific can refer to SpringBoot integration Swagger combat. And the official version 3.0 has been released recently. For details, please refer to: Still manually integrating Swagger? Swagger official Starter is really sweet! .

Knife4j profile

Although directly through Springfox can already achieve SpringBoot access Swagger generated interface documents. But this approach has two drawbacks:

  1. Native interface documentation page presentation is not friendly enough.
  2. It can be cumbersome to use.

Therefore, Knife4j is highly recommended here. Knife4j is a generic solution for Swagger interface document services, with the underlying implementation based on Springfox. The two main features are as follows:

  1. Rewrite the front UI interface, more in line with the people’s use habits.
  2. Fast access is supported and many utility enhancements are provided.
  3. Documentation friendly, direct referenceKnife4jOfficial website documents can complete access.

The cheapest way to get users in is the best way, and Knife4j works very well. More details you can refer to the official documentation xiaoym. Gitee. IO/knife4j/doc… .

Best Practice Guidelines

In fact, SpringBoot’s Controller layer methods already contain details describing this interface. Of course, because we need to add Chinese instructions. So, ideally, the interface documentation would be automatically generated directly from the Controller layer methods, and we would write a Chinese specification for each parameter, and that would be it.

I think a fully self-describing interface is the most reasonable and easiest. But while the ideal is good, the reality is that Springfox doesn’t support it very well. Therefore, we need to find a way to solve this problem in practice. The following will introduce the solutions to some common problems.

How to choose the 2.x and 3.x versions

Knife4j version 2.x corresponds to Springfox version 2.x, which uses the Swagger2 specification, and the corresponding 3.x version uses the OpenAPI3 specification. We don’t need to go into too much detail about these two specifications, except that the OpenAPI3 specification describes interfaces more accurately. For Springfox, the 3.x version also has the advantage of better Bean Validation support, which allows more detailed interface information to be resolved from the interface itself. Therefore, if conditions permit, the 3.x version is strongly recommended! I don’t even think there’s much value in access if it’s 2.x. I’ve always felt that writing comments specifically for a document on an interface that is already self-describing is putting the cart before the horse. Since it is already described, the best solution is always the framework to parse, not the human to write it again!!

The following is a 2.x and 3.x version of the same interface generated interface documentation, I believe you will have a judgment after reading!

2.xVersion:

3.xVersion:

3. Version X parses more interface information and provides more accurate description.

Request body input parameter support is not good enough

For Query Query parameters, Springfox version 3.x already supports them very well, so we can just write the interface as before. However, for request body parameters, the existing framework is not good enough. Among them, the most typical one does not support grouping verification. As a result, the document displays the entire DTO class’s fields and constraints on any interface that uses the DTO to receive parameters. Obviously, this doesn’t make sense, because all packet verification does is make the interface specify that the constraints under the group apply only to that interface.

Is there a perfect solution to this problem? The answer is no, there is only one trade-off. If you are serious about the accuracy of the interface document, you will have to do without grouping validation, which means that each interface request body will be received using a different DTO class to prevent interference. If you don’t care, it’s easier to write it as a group check. At present, our project plans to choose the first method.

If you are not familiar with parameter Validation, you can click here: Spring Validation best practices and implementation principles. Parameter Validation is not that easy! . This annotated approach is strongly recommended for parameter validation. Because only annotations can truly be used to describe the interface.

Access and usage examples

Introduction of depend on

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>3.0.2</version>
</dependency>
Copy the code

Write the interface

Just add a Chinese description for each field.

@RestController
@RequestMapping("/api/person")
@Validated
@API (tags = "Person Management ")
public class PersonController {


    @apiOperation (" Save user ")
    @PostMapping("savePerson")
    public Result<PersonVO> savePerson(@RequestBody @Valid SavePersonDTO person) {
        PersonVO personVO = new PersonVO().setAge(10).setEmail("xxxxx").setId(1L).setName("Ha ha");
        return Result.ok(personVO);
    }

    @apiOperation (" Update user ")
    @PostMapping("updatePerson")
    public Result<PersonVO> updatePerson(@RequestBody @Valid UpdatePersonDTO person) {
        PersonVO personVO = new PersonVO().setAge(10).setEmail("xxxxx").setId(1L).setName("Ha ha");
        return Result.ok(personVO);
    }


    @ ApiOperation (" query person ")
    @GetMapping("queryPerson")
    public Result<List<PersonVO>> queryPerson(
            @ ApiParam (" user id ") @Min(1000) @Max(10000000) Long id,
            @ ApiParam (" name ") @NotNull @Size(min = 2, max = 10) String name,
            @ ApiParam (" age ") @NotNull @Max(200) Integer age,
            @ ApiParam (" email "), @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$") String email) {
        List<PersonVO> list = new ArrayList<>();
        list.add(new PersonVO().setAge(10).setEmail("xxxxx").setId(1L).setName("Ha ha"));
        returnResult.ok(list); }}@Data
@Accessors(chain = true)
@apiModel (" Save user DTO class ")
public class SavePersonDTO {

    @ ApiModelProperty (" name ")
    @NotNull
    @Size(min = 2, max = 10)
    private String name;

    @ ApiModelProperty (" age ")
    @NotNull
    @Max(200)
    private Integer age;

    @ ApiModelProperty (" email "),
    @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")
    private String email;
}

@Data
@Accessors(chain = true)
@apiModel (" Update user DTO class ")
public class UpdatePersonDTO {


    @ ApiModelProperty (" user id ")
    @NotNull
    private Long id;

    @ ApiModelProperty (" name ")
    @Size(min = 2, max = 10)
    private String name;

    @ ApiModelProperty (" age ")
    @Max(200)
    private Integer age;

    @ ApiModelProperty (" email "),
    @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")
    private String email;
}

@Data
@Accessors(chain = true)
@apiModel (" User VO class ")
public class PersonVO {

    @ ApiModelProperty (" user id ")
    private Long id;

    @ ApiModelProperty (" name ")
    private String name;

    @ ApiModelProperty (" age ")
    private Integer age;

    @ ApiModelProperty (" email "),
    private String email;
}

Copy the code

Generally speaking, the interface document function is not required in the production environment. You only need to add the following configuration in the production environment:

springfox:
  documentation:
    enabled: false
Copy the code

Common document annotations

The purpose of using document annotations is to add Chinese instructions, nothing more!

annotations instructions The sample
@Api Mark inControllerIs used to add Chinese description to the controller @API (tags = “Person Management “)
@ApiOperation Annotation on a method to add Chinese to a request @apiOperation (” Save user “)
@ApiParam Annotation on method parameters, used to add Chinese description to request parameters @ ApiParam (” user id “)
@ApiModel Mark inDTOOn the entity class, used to add A Chinese description to the request body @apiModel (” Save user DTO class “)
@ApiModelProperty Mark inDTOTo add a Chinese description to the request body field @ ApiModelProperty (” name “)

Sample screenshots

The source code

Source code address: github.com/chentianmin…

Start the project, visit http://localhost:8080/doc.html to view interface documentation.

Original is not easy, feel that the article is written well small partners, a praise 👍 to encourage it ~

Welcome to my open source project: a lightweight HTTP invocation framework for SpringBoot