Spring Boot 2.x Basic Tutorial: Swagger Interface Classification and Detailed Explanation of Element Sorting Problem

Keywords: Java Spring github SpringBoot Attribute

Previously adopted Spring Boot 2.x basic tutorial: building powerful API documents with Swagger2 In this article, we learned how to use Swagger to automatically generate API documents for Spring Book projects. Many users left messages asking about the organization and sorting of document content. So, I'll start a special article detailing how Swagger organizes the content of documents and how each element controls the order of configuration.

Grouping of interfaces

In Spring Boot, we define interfaces organized by Controller as the first dimension, and the relationship between Controller and specific interfaces is one-to-many. We can define interfaces that belong to the same module in a Controller. By default, Swagger manages interfaces in groups in Controller. This grouping element is called Tag in Wagger, but the relationship between Tag and interface here is not one-to-many, it supports richer many-to-many relationships.

Default grouping

First, let's take a simple example to see how Swagger organizes Tag-interface relationships based on Controller by default. Define two Controllers responsible for the interface between teacher management and student management, such as the following:

@RestController
@RequestMapping(value = "/teacher")
static class TeacherController {

    @GetMapping("/xxx")
    public String xxx() {
        return "xxx";
    }

}

@RestController
@RequestMapping(value = "/student")
static class StudentController {

    @ApiOperation("Get the Student List")
    @GetMapping("/list")
    public String bbb() {
        return "bbb";
    }

    @ApiOperation("Get a list of teachers who teach a student")
    @GetMapping("/his-teachers")
    public String ccc() {
        return "ccc";
    }

    @ApiOperation("Create a student")
    @PostMapping("/aaa")
    public String aaa() {
        return "aaa";
    }

}

After launching the application, we can see that the two Controller s in Swagger are organized as follows:

The figure shows the content and location displayed by Controller in Swagger's default Tag and Spring Boot.

Customize the name of the default group

Next, we can try again to customize Tag through the @Api annotation, such as:

@Api(tags = "Teacher management")
@RestController
@RequestMapping(value = "/teacher")
static class TeacherController {

    // ...

}

@Api(tags = "Student Management")
@RestController
@RequestMapping(value = "/student")
static class StudentController {

    // ...

}

After restarting the application, we see the following grouping content. The tags defined by @Api in the code replace the default teacher-controller and student-controller.

Merge Controller Groups

So far, we've only used one-to-one correspondence between Tag and Controller. Swagger also supports more flexible grouping! From the attributes of @Api annotations, it is believed that smart readers have found that tags attributes are actually array types:

We can aggregate the interfaces in Controller by defining a Tag with the same name. For example, we can define a Tag as "teaching management", so that the group includes all the interfaces of teacher management and student management at the same time.

@Api(tags = {"Teacher management", "Teaching Management"})
@RestController
@RequestMapping(value = "/teacher")
static class TeacherController {

    // ...

}

@Api(tags = {"Student Management", "Teaching Management"})
@RestController
@RequestMapping(value = "/student")
static class StudentController {

    // ...

}

The final results are as follows:

Finer-grained interface grouping

With @Api, you can merge the interfaces in Controller into a Tag, but what if you want to merge them exactly to an interface? For example, there is a need for "teaching management" to include all interfaces in "teacher management" and "access to student lists" in "student management" (not all interfaces).

Then the above implementation can not be satisfied. At this point, we can use the tags attribute in the @ApiOperation annotation to make a finer-grained interface classification definition, such as the requirements above can be written as follows:

@Api(tags = {"Teacher management","Teaching Management"})
@RestController
@RequestMapping(value = "/teacher")
static class TeacherController {

    @ApiOperation(value = "xxx")
    @GetMapping("/xxx")
    public String xxx() {
        return "xxx";
    }

}

@Api(tags = {"Student Management"})
@RestController
@RequestMapping(value = "/student")
static class StudentController {

    @ApiOperation(value = "Get the Student List", tags = "Teaching Management")
    @GetMapping("/list")
    public String bbb() {
        return "bbb";
    }

    @ApiOperation("Get a list of teachers who teach a student")
    @GetMapping("/his-teachers")
    public String ccc() {
        return "ccc";
    }

    @ApiOperation("Create a student")
    @PostMapping("/aaa")
    public String aaa() {
        return "aaa";
    }

}

The effect is as follows:

Sequence of content

After completing the interface grouping, the display order of interface content is a special concern of many users, which mainly involves three aspects: grouping, interface sorting and parameter sorting. Now let's talk about how to configure and use them one by one.

Sorting of Groups

About grouping sort, that is, Tag sort. The current version of Wagger support is not very good, we can find the configuration method about Tag sorting through documentation.

First: native Swagger users can do this in the following ways:

Second: Swagger Starter users can modify their configuration by:

swagger.ui-config.tags-sorter=alpha

Seems to have found hope, but in fact, there is no alternative to this piece, as you can see from the source code:

public enum TagsSorter {
  ALPHA("alpha");

  private final String value;

  TagsSorter(String value) {
    this.value = value;
  }

  @JsonValue
  public String getValue() {
    return value;
  }

  public static TagsSorter of(String name) {
    for (TagsSorter tagsSorter : TagsSorter.values()) {
      if (tagsSorter.value.equals(name)) {
        return tagsSorter;
      }
    }
    return null;
  }
}

Yes, Swagger only offers one option, alphabetical order. So how do we achieve sorting? Here, I give a suggestion that the ranking can be achieved only by the definition of usage without extending the source code: Number the name of Tag. For example:

@Api(tags = {"1-Teacher management","3-Teaching Management"})
@RestController
@RequestMapping(value = "/teacher")
static class TeacherController {

    // ...

}

@Api(tags = {"2-Student Management"})
@RestController
@RequestMapping(value = "/student")
static class StudentController {

    @ApiOperation(value = "Get the Student List", tags = "3-Teaching Management")
    @GetMapping("/list")
    public String bbb() {
        return "bbb";
    }

    // ...

}

Because of the original alphabetical sorting mechanism, adding numbers to the naming to help sorting can solve the grouping problem simply and roughly. The final effect is as follows:

Sorting of interfaces

After completing the grouping sorting problem (although not elegant...), let's look at how each interface in the same grouping can achieve sorting. Similarly, if you consult the document beforehand, you can see that Swagger also provides the corresponding configuration, which is described in two ways below:

First: native Swagger users can do this in the following ways:

Second: Swagger Starter users can modify their configuration by:

swagger.ui-config.operations-sorter=alpha

Fortunately, unlike Tag's sorting configuration, this configuration has no options. It provides two configuration items: alpha and method, which represent sorting by alphabet and method definition, respectively. When we do not configure, the default configuration is alpha. The effects of the two configurations are compared as shown in the following figure:

Sorting of parameters

After sorting the interfaces, the more granular is the sorting of the request parameters. By default, Swagger's presentation of Model parameter content is also alphabetical. So the User object in the previous tutorial is shown in the article as follows:

If we want to show it in the order of member variables defined in Model, we need to set the location by using the position parameter of the @ApiModelProperty annotation, such as:

@Data
@ApiModel(description = "User entity")
public class User {

    @ApiModelProperty(value = "User Number", position = 1)
    private Long id;

    @NotNull
    @Size(min = 2, max = 5)
    @ApiModelProperty(value = "User Name", position = 2)
    private String name;

    @NotNull
    @Max(100)
    @Min(10)
    @ApiModelProperty(value = "User Age", position = 3)
    private Integer age;

    @NotNull
    @Email
    @ApiModelProperty(value = "User Mailbox", position = 4)
    private String email;

}

The final results are as follows:

Summary

This paper introduces the organization and control of interface content in Swagger in detail. Some of the problems are not solved by configuration, or may be lack of in-depth understanding of the document or source content. If the reader has a better implementation plan, welcome to put forward and exchange.

Code examples

The complete project of this article can be viewed in the following chapter2-4 directory in the warehouse:

If you think this article is good, welcome Star support, your attention is my motivation to insist!

Relevant information

Welcome to my public number: Program Ape DD, get exclusive learning resources and daily dry goods push.
If you are interested in my topic, you can also pay attention to my blog: didispace.com

Posted by justinwhite93 on Wed, 09 Oct 2019 10:41:05 -0700