Swagger (OpenAPI) is a programming language-agnostic interface specification used to describe REST apis in projects. Its emergence is mainly to save developers writing interface documentation time, can generate corresponding visual interface documentation according to the annotations in the project.

OpenAPI specification (OpenAPI json)

The OpenAPI specification is a document that describes the functionality of an API. This document is based on XML and attribute annotations in the controller and model. It is a core part of the OpenAPI stream used to drive tools such as SwaggerUI.

The two main Swagger implementation packages in.net are Swashbuckle and NSwag. Today we begin with Swashbuckle.

Basis function

1. Search for Swashbuckle.aspnetcore in package manager and install it.

2. Add the code to the ConfigureServices method in startup. cs.
public void ConfigureServices(IServiceCollection services)
{
	services.AddControllers();
	services.AddSwaggerGen();
}
Copy the code
3. Add code to the Configure method in startup. cs.
app.UseSwagger();
app.UseSwaggerUI(options =>
{
	options.SwaggerEndpoint("/swagger/v1/swagger.json"."v1");
	options.RoutePrefix = string.Empty;
});
Copy the code
4. Modify the launchsettings. json file and change the launchUrl value to index.html
5. Prepare interfaces
[ApiController] public class HomeController : ControllerBase { private readonly ILogger<HomeController> _logger; public HomeController(ILogger<HomeController> logger) { _logger = logger; } /// </summary> /// </summary> /// </returns> [HttpGet("home/ getUser ")] public string getUser () { return "my name is dotnetboy"; } /// <summary> // successful login /// </summary> /// </returns> [HttpPost("home/login")] public String login () {return "login success"; } /// </summary> [HttpDelete("home/{id}")] public string DeleteUser(string ID) {return $"delete success,id={id}"; }}Copy the code
6. Enable XML document output and start the project

Extend the functionality

Project description

AddSwaggerGen(options => {options.SwaggerDoc("v1", new OpenApiInfo {Title = "test interface document ", Version = "v1", Description = "webAPI"}); });Copy the code

The interface group

In real development, if all the interfaces are displayed together, it is very difficult for relevant people to find them. We can group related interfaces according to business logic, such as: login, user, order, goods, and so on.

1. Prepare the packet information feature
// </summary> // </summary> public class GroupInfoAttribute: Attribute {/// <summary> /// Title /// </summary> public string Title {get; set; } /// <summary> // Version // </summary> public string Version {get; set; } /// <summary> /// Description // </summary> public string Description {get; set; }}Copy the code
2. Prepare grouping enumeration
/// </summary> public enum ApiGroupNames {[GroupInfo(Title = "login authentication ", Description =" login related interface ", Version = "v1")] Login, [GroupInfo(Title = "User", Description = "User interface ")] User, [GroupInfo(Title = "User", Description = "Order ")] Order}Copy the code
3. Prepare interface features
/// </summary> public class ApiGroupAttribute: Attribute, IApiDescriptionGroupNameProvider { /// <summary> /// /// </summary> /// <param name="name"></param> public ApiGroupAttribute(ApiGroupNames name) { GroupName = name.ToString(); } /// </summary> /// </summary> public string GroupName {get; set; }}Copy the code
4. Add features to different interfaces
[ApiController] public class HomeController : ControllerBase { private readonly ILogger<HomeController> _logger; public HomeController(ILogger<HomeController> logger) { _logger = logger; } / / / < summary > / / / / / / get the user information < / summary > / / / < returns > < / returns > [HttpGet (" home/getuser ")" [ApiGroup(ApiGroupNames.User)] public string GetUser() { return "my name is dotnetboy"; } /// </summary> // </summary> /// </returns> [HttpPost("home/login")] [ApiGroup(apigroupnames.login)]  public string Login() { return "login success"; } /// <summary> /// delete Order /// </summary> [HttpDelete("home/{id}")] [ApiGroup(apigRoupNames.order)] public String DeleteOrder(string id) { return $"delete success,id={id}"; } /// </summary> /// </summary> [HttpDelete("home/message")] public string DeleteUser(string MSG) {return $" message: {MSG} "; }}Copy the code
5. Change AddSwaggerGen to the ConfigureServices method
AddSwaggerGen(options => {options.SwaggerDoc("v1", new OpenApiInfo {Title = "interface document ", Version = "v1", Description = "webAPI"}); // Generate interface document by traversing all enumerated values of ApiGroupNames, Skip(1) because Enum first FieldInfo is built-in with an Int value typeof(ApiGroupNames).getFields ().skip (1).tolist ().foreach (f => {// get the property var on the enumerated value info = f.GetCustomAttributes(typeof(GroupInfoAttribute), false).OfType<GroupInfoAttribute>().FirstOrDefault(); options.SwaggerDoc(f.Name, new OpenApiInfo { Title = info? .Title, Version = info? .Version, Description = info? .Description }); }); Options. SwaggerDoc("NoGroup", new OpenApiInfo {Title = "NoGroup"}); / / judge interface to which group options. DocInclusionPredicate ((docName, apiDescription) = > {the if (docName = = "NoGroup") {/ / when the packet is NoGroup, Return String.IsNullOrEmpty(apiDescription.GroupName); } else { return apiDescription.GroupName == docName; }}); });Copy the code
Modify the UseSwaggerUI of the Configure method
App.useswaggerui (options => {// Iterating through all enumerated values of ApiGroupNames generates interface document Typeof (ApiGroupNames).getFields ().skip (1).tolist ().foreach (f) Var info = f.goetCustomAttributes (typeof(GroupInfoAttribute), false).OfType<GroupInfoAttribute>().FirstOrDefault(); options.SwaggerEndpoint($"/swagger/{f.Name}/swagger.json", info ! = null ? info.Title : f.Name); }); Options. SwaggerEndpoint ("/swagger NoGroup/swagger. Json ", "no group"); options.RoutePrefix = string.Empty; });Copy the code

Custom UI

A few days ago, front-end colleagues and I joked that Swagger’s native UI is too ugly and not intuitive. If you want to find an interface, you have to shrink and expand it one by one. In short, it is difficult to use.

  1. Not intuitive
  2. Not easy to find

With these two requirements, why not implement your own UI? (A third-party off-the-shelf version was eventually used.)

Swagger UI data source swagger. Json file swagger UI data source swagger UI data source swagger.

1. Prepare a beautiful single page (found online)

2, put the content of the single page into the project (remember to enable static file reading)
app.UseStaticFiles();
Copy the code

3. Specify a single page as a UI page.
app.UseSwaggerUI(options =>
{
	options.IndexStream = () => GetType().Assembly.GetManifestResourceStream("h.swagger.Swagger.index.html");
});
Copy the code
4. Process swagger.json data source in a single page.
5. Final effect

Swagger UI has many functions, such as details and debugging. There’s a lot of work to do if you want to implement a UI yourself. As a result, I chose Knife4j, a third-party open source project that never goes out of style.

Is also very simple to use and reference the package first: IGeekFan. AspNetCore. Knife4jUI, then at Startup. The Configure, app. UseSwaggerUI replaced by:

app.UseKnife4UI(c =>
{
	c.RoutePrefix = string.Empty;
	c.SwaggerEndpoint($"/swagger/v1/swagger.json", "h.swagger.webapi v1");
});
Copy the code