API 2Doc API API API API API API API API API API API API API API API API API API API
This project has been put on Github, if you need source code, please click here
directory
- Project background
- Api2Doc profile
- Introduce Api2Doc dependencies
- Enable the Api2Doc service
- Add a document annotation to the Controller class
- @api2doc annotation details
- @apicomment Notes details
- @apierror annotation details
- Sort document menu items
- Add custom documents
- Customize the welcome page of the document
- Customize the title and icon of the document
- Close the Api2Doc service
Project background
In the development process of Internet/mobile Internet software, most r&d teams have a clear division of labor between the front and back. Background engineers are responsible for the development of server systems, generally providing HTTP/HTTPS Restful API interfaces, while front engineers are responsible for the development of Android, iOS and H5 pages. The Restful API interface needs to be invoked.
This requires a Restful API document to help both parties communicate and agree on the API interface. Typically, the documentation falls to the backend engineers, who provide the API.
But the problem is to write a Restful API documentation is a tedious and time consuming, also of no help to the improvement of technical ability drudgery, especially in is the needs of rapid iteration and frequent changes in the project, change the code and synchronous documents, which point correction or changed leakage is likely to be produced before and after the implementation of inconsistencies, lead to find bugs when alignment, Ultimately, the back office engineer will have to carry the pan. .
Therefore, there are some open source projects that automatically generate Restful API documents according to the code. A good combination with Spring Boot is Swagger2. Swagger2 automatically generates API documents by reading the annotation information in the Controller code. You can save a lot of manual documentation.
The author of this project also used Swagger2 before, but found that Swagger2 is also used in many ways:
First, the Swagger2 annotation is very bloated, let’s look at this code:
@RestController @RequestMapping(value = "/user3") public class UserController2Swagger2 { @ApiOperation(value = "Get user details from specified ID ", notes =" Get user details from specified USER ID ", HttpMethod = "GET") @apiIMPLicitParams ({@apiimplicitParam (name = "userName", value = "userName", paramType = "query", Required = true, dataType = "String"), @APIIMPLICITParam (name = "password", value = "user password", paramType = "query", Required = true, dataType = "String")}) @requestMapping (name = "user registration ", value = "/regist", method = RequestMethod.GET) public UserInfo regist(@RequestParam("userName") String userName, @RequestParam("password") String password) { return new UserInfo(); }}Copy the code
@ApiOperation and @APIIMPLICITParam are annotations provided by Swagger2 to define API information. In fact, the API Method itself contains a lot of information, such as HTTP Method, parameter name, parameter type, etc. For example, @apiIMPLICITParam, except the value attribute is useful, all the other descriptions are repeated.
Second, Swagger2’s page layout is not very friendly, it is a vertical arrangement, which is not conducive to the presentation of information. And look at the API details have to unfold one by one, the middle is also mixed with the test function, anyway as a document is not easy to read; As for testing tools… Now there are many professional testing tools, and testers don’t seem to choose them.
Third, Swagger2 still has a lot of details to do, for example, look at this figure:
The API in the red box corresponds to the same method. The only reason there are so many is because the method is not specified:
@RestController @RequestMapping(value = "/user2") public class UserController2Swagger2 { @RequestMapping(value = "/do_something") public void doSomethingRequiredLogon() {} }Copy the code
(When method is not specified, Spring Boot makes this interface support all methods by default.)
So instead of putting up with Swagger2’s frustrations for a long time, I decided to spend some time building a more useful “automated documentation system,” and this project was born: Api2Doc.
Api2Doc profile
API 2Doc focuses on the automatic generation of Restful API documents. It works in a similar way to Swagger2, but it is much better than Swagger2 by analyzing information in the Controller through reflection.
The biggest difference: Api2Doc writes a lot less code than Swagger2.
For example, the code to use Swagger2 looks like this:
@restController @requestMapping (value = "/user") Public class UserController {@apiOperation (value = "add user", HttpMethod = "POST", notes = "Add user to user group, @apiIMPLICITParams ({@apiIMPLICITParam (name = "group", value = "user group name ", paramType = "query", Required = true, dataType = "String"), @APIIMPLICITParam (name = "name", value = "username ", paramType = "query", Required = true, dataType = "String"), @APIIMPLICITParam (name = "type", value = "user type", paramType = "query", required = true, dataType = "String") }) @RequestMapping(value = "/addUser", method = RequestMethod.POST) public User addUser(String group, String name, String type) { return null; // TODO: not implemented yet. }}Copy the code
Let’s look at the code decorated with the Api2Doc annotation:
@Api2Doc(id = "users") @ApiComment(seeClass = User.class) @RestController @RequestMapping(value = "/api2doc/demo2") Public class UserController2 {@apicomment (" Add a user to a user group @requestMapping (name = "add user", value = "/user", method = RequestMethod.POST) public User addUser(String group, String name, String type) { return null; // TODO: not implemented yet. } // Other methods, here omitted... }Copy the code
See, Api2Doc only needs a little bit of code to add @api2doc@apicomment annotations to the method, but the documentation it generates is unambiguous, as shown below:
Some friends may feel strange: the documentation page instructions, sample values, etc., are not written in the code, ah, these come from?
This goes to the heart of Api2Doc’s design philosophy: it automatically collects the information needed to generate documents through intelligent analysis as much as possible, thereby saving users from writing code.
To answer this question directly, please note that there is a comment on this class:
@ApiComment(seeClass = User.class)
Copy the code
When you encounter no instructions on an API method, refer to the instructions defined in the User class.
Here is the code for the User class:
Public class User {@apicomment (value = "User id", sample = "123") private Long ID; @apicomment (value = "username ", sample = "terran4j") private String name; @apicomment (value = "account password ", sample =" sdfi23SKvs ") private String password; @apicomment (value = "user group ", sample =" r&d group ") private String group; @apicomment (value = "UserType ", sample = "admin") private UserType type; @apicomment (value = "Deleted ", sample = "true") @restPackignore private Boolean deleted; @apicomment (value = "create time \n also register time." ) private Date createTime; // omit getter/setter methods. }Copy the code
Do you see that? Parameters in API methods that have the same name as an attribute of the User class are automatically populated with the @apicomment specification for the class attribute.
This also makes practical business logic. Because in most projects, some fields will be used in multiple entity classes and API methods, there is no need to write their descriptions repeatedly, just define them in one place and refer to them elsewhere.
Of course, this is just one of the many ways Api2Doc is better than Swagger2.
Here’s a comprehensive overview of its use, hopefully to help developers get out of the documentation grind.
Introduce Api2Doc dependencies
If it is Maven, add the dependency to pom.xml as follows:
<dependency>
<groupId>com.github.terran4j</groupId>
<artifactId>terran4j-commons-api2doc</artifactId>
<version>${api2doc.version}</version>
</dependency>
Copy the code
If it is gradle, add a dependency to build.gradle as follows:
compile "com.github.terran4j:terran4j-commons-api2doc:${api2doc.version}"
Copy the code
${api2doc.version} latest stable version, please refer to here
Enable the Api2Doc service
This tutorial’s sample code in the SRC/test/Java directory. Com terran4j. Demo. Api2doc, you can also get to from here.
First, we need to add the @Enableapi2doc annotation to the class with the @SpringBootApplication annotation to enable the Api2Doc service, as shown in the following code:
package com.terran4j.demo.api2doc; import com.terran4j.commons.api2doc.config.EnableApi2Doc; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; // Document access address: http://localhost:8080/api2doc/home.html @EnableApi2Doc @SpringBootApplication public class Api2DocDemoApp { public static void main(String[] args) { SpringApplication.run(Api2DocDemoApp.class, args); }}Copy the code
Add a document annotation to the Controller class
We then add the @API2doc annotation to the RestController class, and add @apicomment annotation where documentation is required as follows:
package com.terran4j.demo.api2doc; import com.terran4j.commons.api2doc.annotations.Api2Doc; import com.terran4j.commons.api2doc.annotations.ApiComment; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @Api2Doc(id = "demo1", Name = "User interface 1") @apicomment (seeClass = user.class) @restController @requestMapping (value = "/ API2doc /demo1") public Class UserController1 {@apicomment (" Add a new user." ) @requestMapping (name = "new user", value = "/user", method = requestmethod. POST) public user addUser(String group) @requestMethod. POST String name, @apicomment (" UserType ") UserType type) {return null; // TODO: not implemented yet. }}Copy the code
The return type of this method is defined as User:
Public class User {@apicomment (value = "User id", sample = "123") private Long ID; @apicomment (value = "username ", sample = "terran4j") private String name; @apicomment (value = "account password ", sample =" sdfi23SKvs ") private String password; @apicomment (value = "user group ", sample =" r&d group ") private String group; @apicomment (value = "UserType ", sample = "admin") private UserType type; @apicomment (value = "Deleted ", sample = "true") @restPackignore private Boolean deleted; @apicomment (value = "create time \n also register time." ) private Date createTime; // omit getter/setter methods. }Copy the code
And the type of the type attribute, the UserType class is defined as:
package com.terran4j.demo.api2doc; import com.terran4j.commons.api2doc.annotations.ApiComment; Public enum UserType {@apicOMment (" administrator ") admin, @apicomment (" user ") user}Copy the code
After writing the code, we run the main function to access the Api2Doc home page:
http://localhost:8080/api2doc/home.html
Copy the code
The document page is as follows:
Api2Doc service works, simple as that!
@api2doc annotation details
Api2Doc has three annotations: @api2doc, @apicomment and @apiError.
@API2doc is used to control the generation of documents.
The Api2Doc service scans all Controller classes in the Spring container. Only classes with @api2doc on them are generated. A class corresponds to the first level menu item on the left side of the document page. The name attribute of @API2doc represents the name of the menu item.
The Api2Doc service scans all @requestmapping methods of the class. Each such method corresponds to a secondary menu item on the left side of the document page. The menu item name takes the name attribute of @requestMapping, although you can still redefine it on the method using the name attribute of @API2Doc.
@apicomment Notes details
ApiComment is used to describe an API. It can be modified in many ways:
- Class, indicating that this set of API interface specification;
- The API interface is specified in a method.
- The request parameters of the API interface are described.
- Attribute on a return type property that describes the return field of the API interface.
- Pertaining to an enumeration item, indicating that the enumeration item is specified;
If an attribute or parameter field with the same name and meaning has already been defined elsewhere, the @apicomment seeClass attribute can be used to represent the field with the same name as the specified class, so as in this code:
@Api2Doc(id = "demo1", Name = "User interface 1") @apicomment (seeClass = user.class) @restController @requestMapping (value = "/ API2doc /demo1") public Class UserController1 {@apicomment (" Add a new user." ) @requestMapping (name = "new user", value = "/user", method = requestmethod. POST) public user addUser(String group) @requestMethod. POST String name, UserType type) { return null; // TODO: not implemented yet. }}Copy the code
@apicomment (seeClass = user.class); @apicomment (seeClass = User); So as long as the User class has a group, name,type field and the @apicomment statement is ok.
@apierror annotation details
@ApiError Defines error codes. Some API methods may generate errors during the execution of service logic. If an error occurs, the returned packets contain error codes to facilitate the client to further process the error codes.
The following code demonstrates the use of @apierror:
@api2doc (id = "demo", name = "user interface ", order = 0) @ApiComment(seeClass = User.class) @RestController @RequestMapping(value = "/src/test/resources/demo") public Class UserController {@api2doc (order = 50) @apicomment ") @apiError (value = "user.not. Found ", comment = "This user does not exist!" ) @apiError (value = "admin.cant. Delete ", comment = "Cannot delete admin user!" ) @requestMapping (name = "/user/{id}", value = "/user/{id}", method = RequestMethod.DELETE) public void delete(@PathVariable("id") Long id) { } }Copy the code
The value attribute of @APIError indicates the error code, and comment indicates the description of the error code.
The error code message is displayed at the very end of the document as follows:
Sort document menu items
We can sort the menu items using the order attribute in @api2doc. The smaller the order value, the higher the order, as in this code:
package com.terran4j.demo.api2doc; import com.terran4j.commons.api2doc.annotations.Api2Doc; import com.terran4j.commons.api2doc.annotations.ApiComment; 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.RestController; import java.util.List; @api2doc (id = "demo2", name = "userinterface 2", order = 1) @ApiComment(seeClass = User.class) @RestController @RequestMapping(value = "/api2doc/demo2") public class UserController2 {@api2doc (order = 10) @apicomment (" Add a new user." ) @requestMapping (name = "new user", value = "/user", Method = requestMethod. POST) public User addUser(@apicomment (" username ") String name, @apicomment (" username ") String name, @apicomment (" UserType ") UserType type) {return null; // TODO: not implemented yet. } @api2doc (order = 20) @apicomment @requestMapping (name = "query a user ", value = "/user/{id}", method = RequestMethod.GET) public User getUser(@PathVariable("id") Long id) { return null; // TODO: not implemented yet. } @api2doc (order = 30) @apicomment ) @requestMapping (name = "query user list ", value = "/users", method = RequestMethod.GET) public List<User> getUsers() { return null; // TODO: not implemented yet. } @api2doc (order = 40) @apicomment (" Query information about all users in a specified group based on the group name." ) @requestMapping (name = "query user group ", value = "/group/{group}", method = RequestMethod.GET) public UserGroup getGroup(@PathVariable("group") String group) { return null; // TODO: not implemented yet. }}Copy the code
The result displayed is:
@api2doc on the class can also sort the first level menu, but the rules are the same, I won’t show you here.
Add custom documents
Sometimes the auto-generated API documentation doesn’t seem perfect. Maybe we want to add something else, like background on the project, technical architecture, etc. How about this?
Api2Doc allows documentation to be written manually in MD syntax and integrated into automatically generated API documentation as follows:
First, define the id attribute on @API2doc on the class, for example for the following class:
package com.terran4j.demo.api2doc; import com.terran4j.commons.api2doc.annotations.Api2Doc; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @Api2Doc(id = "demo3", Name = "userController ") @restController@requestMapping (value = "/ api2Doc /demo3") public class UserController3 {@api2doc (order) = 10) @requestMapping (name = "1", Value = "/m1") public void m1() {} @api2doc (order = 20) @requestMapping (name = "1", value = "/m2") public void m2() { } }Copy the code
@api2doc (id = “Demo3 “, name =” User interface 3″) : Indicates that the ID of user Interface 3 in the corresponding level-1 menu is Demo3.
We then create the directory api2doc/demo3 in SRC /main/resources. Api2doc is fixed and demo3 indicates that the documents in this directory are added to the first-level document menu with id demo3.
Then we write the md format document in the API2doc /demo3 directory, as shown below:
The file name is in the format of ${order}-${document name}.md, where the number before the – sign indicates the order of the document, the same as the order attribute in @api2doc, and the – sign is followed by the document name, which is the name of the secondary menu.
Therefore, the final document looks like this:
See, the hand-written supplementary documentation combined with the auto-generated API documentation, sorted by order, looks pretty neat.
Customize the welcome page of the document
Every visit to the document page, http://localhost:8080/api2doc/home.html, in the middle of the content is very simple:
Welcome to Api2Doc!Copy the code
That might seem a little bad, but that’s okay, we can write our own welcome page.
To do this, simply create a file called welcome.md in the api2doc directory of the SRC /main/resources directory (the name is fixed) and write the content in the MD syntax.
Configure the document title and icon
You can configure the document title and icon in application.yml as follows:
Api2doc: title: api2doc sample project - interface document icon: https://spring.io/img/homepage/icon-spring-framework.svgCopy the code
The icon is a full path URL or a relative path URL of the site.
The configuration results are as follows:
Close the Api2Doc service
You configure the API2doc. enabled property in application.yml to turn on or off the API2doc service, as follows:
# api2doc: title: api2doc example project https://spring.io/img/homepage/icon-spring-framework.svg - online environment spring: # profiles: online api2doc: enabled: falseCopy the code
Api2doc. enabled False indicates that the API2doc service is disabled. No write or true indicates that the api2doc service is enabled.
Since the Api2Doc service does not have access verification, it is recommended that you enable the Api2Doc service only in a trusted network environment, such as the corporate Intranet.