{"id":1158,"date":"2025-05-27T14:48:09","date_gmt":"2025-05-27T06:48:09","guid":{"rendered":"https:\/\/www.hyy.net\/?p=1158"},"modified":"2025-05-27T14:48:09","modified_gmt":"2025-05-27T06:48:09","slug":"ultimate-asp-net-core-web-api-30-documenting-api-with-swagger","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=1158","title":{"rendered":"Ultimate ASP.NET Core Web API 30 DOCUMENTING API WITH SWAGGER"},"content":{"rendered":"<p>30 DOCUMENTING API WITH SWAGGER<br \/>\n30 \u4f7f\u7528 SWAGGER \u7f16\u5199 API \u6587\u6863<\/p>\n<p>Developers who consume our API might be trying to solve important business problems with it. Hence, it is very important for them to understand how to use our API effectively. This is where API documentation comes into the picture.\u200c<br \/>\n\u4f7f\u7528\u6211\u4eec\u7684 API \u7684\u5f00\u53d1\u4eba\u5458\u53ef\u80fd\u6b63\u5728\u5c1d\u8bd5\u4f7f\u7528\u5b83\u6765\u89e3\u51b3\u91cd\u8981\u7684\u4e1a\u52a1\u95ee\u9898\u3002\u56e0\u6b64\uff0c\u4ed6\u4eec\u4e86\u89e3\u5982\u4f55\u6709\u6548\u5730\u4f7f\u7528\u6211\u4eec\u7684 API \u975e\u5e38\u91cd\u8981\u3002\u8fd9\u5c31\u662f API \u6587\u6863\u7684\u7528\u6b66\u4e4b\u5730\u3002<\/p>\n<p>API documentation is the process of giving instructions on how to effectively use and integrate an API. Hence, it can be thought of as a concise reference manual containing all the information required to work with the API, with details about functions, classes, return types, arguments, and more, supported by tutorials and examples.<br \/>\nAPI \u6587\u6863\u662f\u63d0\u4f9b\u6709\u5173\u5982\u4f55\u6709\u6548\u4f7f\u7528\u548c\u96c6\u6210 API \u7684\u8bf4\u660e\u7684\u8fc7\u7a0b\u3002\u56e0\u6b64\uff0c\u5b83\u53ef\u4ee5\u88ab\u8ba4\u4e3a\u662f\u4e00\u672c\u7b80\u660e\u7684\u53c2\u8003\u624b\u518c\uff0c\u5176\u4e2d\u5305\u542b\u4f7f\u7528 API \u6240\u9700\u7684\u6240\u6709\u4fe1\u606f\uff0c\u4ee5\u53ca\u6709\u5173\u51fd\u6570\u3001\u7c7b\u3001\u8fd4\u56de\u7c7b\u578b\u3001\u53c2\u6570\u7b49\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5e76\u9644\u6709\u6559\u7a0b\u548c\u793a\u4f8b\u3002<\/p>\n<p>So, having the proper documentation for our API enables consumers to integrate our APIs as quickly as possible and move forward with their development. Furthermore, this also helps them understand the value and usage of our API, improves the chances for our API\u2019s adoption, and makes our APIs easier to maintain and support.<br \/>\n\u56e0\u6b64\uff0c\u4e3a\u6211\u4eec\u7684 API \u63d0\u4f9b\u9002\u5f53\u7684\u6587\u6863\u4f7f\u6d88\u8d39\u8005\u80fd\u591f\u5c3d\u5feb\u96c6\u6210\u6211\u4eec\u7684 API \u5e76\u7ee7\u7eed\u8fdb\u884c\u5f00\u53d1\u3002\u6b64\u5916\uff0c\u8fd9\u8fd8\u53ef\u4ee5\u5e2e\u52a9\u4ed6\u4eec\u4e86\u89e3\u6211\u4eec API \u7684\u4ef7\u503c\u548c\u7528\u6cd5\uff0c\u63d0\u9ad8\u6211\u4eec API \u88ab\u91c7\u7528\u7684\u673a\u4f1a\uff0c\u5e76\u4f7f\u6211\u4eec\u7684 API \u66f4\u6613\u4e8e\u7ef4\u62a4\u548c\u652f\u6301\u3002<\/p>\n<h2>30.1 About Swagger<\/h2>\n<p>30.1 \u5173\u4e8e Swagger<\/p>\n<p>Swagger is a language-agnostic specification for describing REST APIs. Swagger is also referred to as OpenAPI. It allows us to understand the capabilities of a service without looking at the actual implementation code.\u200c<br \/>\nSwagger \u662f\u7528\u4e8e\u63cf\u8ff0 REST API \u7684\u4e0e\u8bed\u8a00\u65e0\u5173\u7684\u89c4\u8303\u3002Swagger \u4e5f\u79f0\u4e3a OpenAPI\u3002\u5b83\u5141\u8bb8\u6211\u4eec\u4e86\u89e3\u670d\u52a1\u7684\u529f\u80fd\uff0c\u800c\u65e0\u9700\u67e5\u770b\u5b9e\u9645\u7684\u5b9e\u73b0\u4ee3\u7801\u3002<\/p>\n<p>Swagger minimizes the amount of work needed while integrating an API. Similarly, it also helps API developers document their APIs quickly and accurately.<br \/>\nSwagger \u6700\u5927\u9650\u5ea6\u5730\u51cf\u5c11\u4e86\u96c6\u6210 API \u65f6\u6240\u9700\u7684\u5de5\u4f5c\u91cf\u3002\u540c\u6837\uff0c\u5b83\u8fd8\u53ef\u4ee5\u5e2e\u52a9 API \u5f00\u53d1\u4eba\u5458\u5feb\u901f\u51c6\u786e\u5730\u8bb0\u5f55\u4ed6\u4eec\u7684 API\u3002<\/p>\n<p>Swagger Specification is an important part of the Swagger flow. By default, a document named swagger.json is generated by the Swagger tool which is based on our API. It describes the capabilities of our API and how to access it via HTTP.<br \/>\nSwagger \u89c4\u8303\u662f Swagger \u6d41\u7a0b\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u540d\u4e3a swagger.json \u7684\u6587\u6863\u7531\u57fa\u4e8e\u6211\u4eec\u7684 API \u7684 Swagger \u5de5\u5177\u751f\u6210\u3002\u5b83\u63cf\u8ff0\u4e86\u6211\u4eec\u7684 API \u7684\u529f\u80fd\u4ee5\u53ca\u5982\u4f55\u901a\u8fc7 HTTP \u8bbf\u95ee\u5b83\u3002<\/p>\n<h2>30.2 Swagger Integration Into Our Project<\/h2>\n<p>30.2 Swagger \u96c6\u6210\u5230\u6211\u4eec\u7684\u9879\u76ee\u4e2d<\/p>\n<p>We can use the Swashbuckle package to easily integrate Swagger into our\u200c .NET Core Web API project. It will generate the Swagger specification for the project as well. Additionally, the Swagger UI is also contained within Swashbuckle.<br \/>\n\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 Swashbuckle \u5305\u8f7b\u677e\u5730\u5c06 Swagger \u96c6\u6210\u5230\u6211\u4eec\u7684 .NET Core Web API \u9879\u76ee\u4e2d\u3002\u5b83\u8fd8\u5c06\u4e3a\u9879\u76ee\u751f\u6210 Swagger \u89c4\u8303\u3002\u6b64\u5916\uff0cSwagger UI \u4e5f\u5305\u542b\u5728 Swashbuckle \u4e2d\u3002<\/p>\n<p>There are three main components in the Swashbuckle package:<br \/>\nSwashbuckle \u5305\u4e2d\u6709\u4e09\u4e2a\u4e3b\u8981\u7ec4\u4ef6\uff1a<\/p>\n<p>\u2022 Swashbuckle.AspNetCore.Swagger: This contains the Swagger object model and the middleware to expose SwaggerDocument objects as JSON.<br \/>\nSwashbuckle.AspNetCore.Swagger\uff1a\u8fd9\u5305\u542b Swagger \u5bf9\u8c61\u6a21\u578b\u548c\u7528\u4e8e\u5c06 SwaggerDocument \u5bf9\u8c61\u516c\u5f00\u4e3a JSON \u7684\u4e2d\u95f4\u4ef6\u3002<\/p>\n<p>\u2022 Swashbuckle.AspNetCore.SwaggerGen: A Swagger generator that builds SwaggerDocument objects directly from our routes, controllers, and models.<br \/>\nSwashbuckle.AspNetCore.SwaggerGen\uff1a\u4e00\u4e2a Swagger \u751f\u6210\u5668\uff0c\u53ef\u76f4\u63a5\u4ece\u6211\u4eec\u7684\u8def\u7531\u3001\u63a7\u5236\u5668\u548c\u6a21\u578b\u6784\u5efa SwaggerDocument \u5bf9\u8c61\u3002<\/p>\n<p>\u2022 Swashbuckle.AspNetCore.SwaggerUI: An embedded version of the Swagger UI tool. It interprets Swagger JSON to build a rich, customizable experience for describing web API functionality.<br \/>\nSwashbuckle.AspNetCore.SwaggerUI\uff1aSwagger UI \u5de5\u5177\u7684\u5d4c\u5165\u5f0f\u7248\u672c\u3002\u5b83\u89e3\u91ca Swagger JSON \u4ee5\u6784\u5efa\u4e30\u5bcc\u7684\u53ef\u81ea\u5b9a\u4e49\u4f53\u9a8c\uff0c\u7528\u4e8e\u63cf\u8ff0 Web API \u529f\u80fd\u3002<\/p>\n<p>So, the first thing we are going to do is to install the required library in the main project. Let\u2019s open the Package Manager Console window and type the following command:<br \/>\n\u6240\u4ee5\uff0c\u6211\u4eec\u8981\u505a\u7684\u7b2c\u4e00\u4ef6\u4e8b\u662f\u5728\u4e3b\u9879\u76ee\u4e2d\u5b89\u88c5\u6240\u9700\u7684\u5e93\u3002\u8ba9\u6211\u4eec\u6253\u5f00 Package Manager Console \u7a97\u53e3\u5e76\u952e\u5165\u4ee5\u4e0b\u547d\u4ee4\uff1a<\/p>\n<pre><code>PM&gt; Install-Package Swashbuckle.AspNetCore<\/code><\/pre>\n<p>After a couple of seconds, the package will be installed. Now, we have to configure the Swagger Middleware. To do that, we are going to add a new method in the ServiceExtensions class:<br \/>\n\u51e0\u79d2\u949f\u540e\uff0c\u5c06\u5b89\u88c5\u8be5\u8f6f\u4ef6\u5305\u3002\u73b0\u5728\uff0c\u6211\u4eec\u5fc5\u987b\u914d\u7f6e Swagger \u4e2d\u95f4\u4ef6\u3002\u4e3a\u6b64\uff0c\u6211\u4eec\u5c06\u5728 ServiceExtensions \u7c7b\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u65b0\u65b9\u6cd5\uff1a<\/p>\n<pre><code>public static void ConfigureSwagger(this IServiceCollection services) { services.AddSwaggerGen(s =&gt; { s.SwaggerDoc(&quot;v1&quot;, new OpenApiInfo { Title = &quot;Code Maze API&quot;, Version = &quot;v1&quot; }); s.SwaggerDoc(&quot;v2&quot;, new OpenApiInfo { Title = &quot;Code Maze API&quot;, Version = &quot;v2&quot; }); }); }<\/code><\/pre>\n<p>We are creating two versions of SwaggerDoc because if you remember, we have two versions for the Companies controller and we want to separate them in our documentation.<br \/>\n\u6211\u4eec\u6b63\u5728\u521b\u5efa\u4e24\u4e2a\u7248\u672c\u7684 SwaggerDoc\uff0c\u56e0\u4e3a\u5982\u679c\u60a8\u8fd8\u8bb0\u5f97\uff0c\u6211\u4eec\u6709\u4e24\u4e2a\u7248\u672c\u7528\u4e8e Companies \u63a7\u5236\u5668\uff0c\u6211\u4eec\u5e0c\u671b\u5728\u6211\u4eec\u7684\u6587\u6863\u4e2d\u5c06\u5b83\u4eec\u5206\u5f00\u3002<\/p>\n<p>Also, we need an additional namespace:<br \/>\n\u6b64\u5916\uff0c\u6211\u4eec\u8fd8\u9700\u8981\u4e00\u4e2a\u989d\u5916\u7684\u547d\u540d\u7a7a\u95f4\uff1a<\/p>\n<pre><code>using Microsoft.OpenApi.Models;<\/code><\/pre>\n<p>The next step is to call this method in the Program class:<br \/>\n\u4e0b\u4e00\u6b65\u662f\u5728 Program \u7c7b\u4e2d\u8c03\u7528\u6b64\u65b9\u6cd5\uff1a<\/p>\n<pre><code>builder.Services.ConfigureSwagger();<\/code><\/pre>\n<p>And in the middleware part of the class, we are going to add it to the application\u2019s execution pipeline together with the UI feature:<br \/>\n\u5728\u7c7b\u7684\u4e2d\u95f4\u4ef6\u90e8\u5206\uff0c\u6211\u4eec\u5c06\u5b83\u4e0e UI \u529f\u80fd\u4e00\u8d77\u6dfb\u52a0\u5230\u5e94\u7528\u7a0b\u5e8f\u7684\u6267\u884c\u7ba1\u9053\u4e2d\uff1a<\/p>\n<pre><code>app.UseSwagger(); app.UseSwaggerUI(s =&gt; { s.SwaggerEndpoint(&quot;\/swagger\/v1\/swagger.json&quot;, &quot;Code Maze API v1&quot;); s.SwaggerEndpoint(&quot;\/swagger\/v2\/swagger.json&quot;, &quot;Code Maze API v2&quot;); });<\/code><\/pre>\n<p>Finally, let\u2019s slightly modify the Companies and CompaniesV2 controllers:<br \/>\n\u6700\u540e\uff0c\u8ba9\u6211\u4eec\u7a0d\u5fae\u4fee\u6539\u4e00\u4e0b Companies \u548c CompaniesV2 \u63a7\u5236\u5668\uff1a<\/p>\n<pre><code>[Route(&quot;api\/companies&quot;)] [ApiController] [ApiExplorerSettings(GroupName = &quot;v1&quot;)] public class CompaniesController : ControllerBase [Route(&quot;api\/companies&quot;)] [ApiController] [ApiExplorerSettings(GroupName = &quot;v2&quot;)] public class CompaniesV2Controller : ControllerBase<\/code><\/pre>\n<p>With this change, we state that the CompaniesController belongs to group v1 and the CompaniesV2Controller belongs to group v2. All the other controllers will be included in both groups because they are not versioned. Which is what we want.<br \/>\n\u901a\u8fc7\u6b64\u66f4\u6539\uff0c\u6211\u4eec\u58f0\u660e CompaniesController \u5c5e\u4e8e\u7ec4 v1\uff0c\u800c CompaniesV2Controller \u5c5e\u4e8e\u7ec4 v2\u3002\u6240\u6709\u5176\u4ed6\u63a7\u5236\u5668\u90fd\u5c06\u5305\u542b\u5728\u8fd9\u4e24\u4e2a\u7ec4\u4e2d\uff0c\u56e0\u4e3a\u5b83\u4eec\u672a\u8fdb\u884c\u7248\u672c\u63a7\u5236\u3002\u8fd9\u5c31\u662f\u6211\u4eec\u60f3\u8981\u7684\u3002<\/p>\n<p>And that is all. We have prepared the basic configuration.<br \/>\n\u5c31\u8fd9\u6837\u3002\u6211\u4eec\u5df2\u7ecf\u51c6\u5907\u597d\u4e86\u57fa\u672c\u914d\u7f6e\u3002<\/p>\n<p>Now, we can start our app, open the browser, and navigate to <a href=\"https:\/\/localhost:5001\/swagger\/v1\/swagger.json\">https:\/\/localhost:5001\/swagger\/v1\/swagger.json<\/a>. Once the page is up, you are going to see a json document containing all the controllers and actions without the v2 companies controller. Of course, if you change v1 to v2 in the URL, you are going to see all the controllers \u2014 including v2 companies, but without v1 companies.<br \/>\n\u73b0\u5728\uff0c\u6211\u4eec\u53ef\u4ee5\u542f\u52a8\u6211\u4eec\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u6253\u5f00\u6d4f\u89c8\u5668\uff0c\u7136\u540e\u5bfc\u822a\u5230 <a href=\"https:\/\/localhost:5001\/swagger\/v1\/swagger.json\u3002\u9875\u9762\u6253\u5f00\u540e\uff0c\u60a8\u5c06\u770b\u5230\u4e00\u4e2a\">https:\/\/localhost:5001\/swagger\/v1\/swagger.json\u3002\u9875\u9762\u6253\u5f00\u540e\uff0c\u60a8\u5c06\u770b\u5230\u4e00\u4e2a<\/a> json \u6587\u6863\uff0c\u5176\u4e2d\u5305\u542b\u6240\u6709\u63a7\u5236\u5668\u548c\u4f5c\uff0c\u4f46\u6ca1\u6709 v2 companies \u63a7\u5236\u5668\u3002\u5f53\u7136\uff0c\u5982\u679c\u60a8\u5728 URL \u4e2d\u5c06 v1 \u66f4\u6539\u4e3a v2\uff0c\u60a8\u5c06\u770b\u5230\u6240\u6709\u63a7\u5236\u5668 \u2014 \u5305\u62ec v2 \u516c\u53f8\uff0c\u4f46\u6ca1\u6709 v1 \u516c\u53f8\u3002<\/p>\n<p>Additionally, let\u2019s navigate to<br \/>\n\u6b64\u5916\uff0c\u8ba9\u6211\u4eec\u5bfc\u822a\u5230<br \/>\n<a href=\"https:\/\/localhost:5001\/swagger\/index.html\">https:\/\/localhost:5001\/swagger\/index.html<\/a>:<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3001.jpg\" alt=\"alt text\" \/><\/p>\n<p>Also if we expand the Schemas part, we are going to find the DTOs that we used in our project.<br \/>\n\u6b64\u5916\uff0c\u5982\u679c\u6211\u4eec\u6269\u5c55 Schemas \u90e8\u5206\uff0c\u6211\u4eec\u5c06\u627e\u5230\u6211\u4eec\u5728\u9879\u76ee\u4e2d\u4f7f\u7528\u7684 DTO\u3002<\/p>\n<p>If we click on a specific controller to expand its details, we are going to see all the actions inside:<br \/>\n\u5982\u679c\u6211\u4eec\u5355\u51fb\u7279\u5b9a\u63a7\u5236\u5668\u4ee5\u5c55\u5f00\u5176\u8be6\u7ec6\u4fe1\u606f\uff0c\u6211\u4eec\u5c06\u770b\u5230\u5176\u4e2d\u7684\u6240\u6709\u4f5c\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3002.jpg\" alt=\"alt text\" \/><\/p>\n<p>Once we click on an action method, we can see detailed information like parameters, response, and example values. There is also an option to try out each of those action methods by clicking the Try it out button.<br \/>\n\u5355\u51fb\u4f5c\u65b9\u6cd5\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u53c2\u6570\u3001\u54cd\u5e94\u548c\u793a\u4f8b\u503c\u7b49\u8be6\u7ec6\u4fe1\u606f\u3002\u8fd8\u6709\u4e00\u4e2a\u9009\u9879\uff0c\u53ef\u4ee5\u901a\u8fc7\u5355\u51fb Try it out \uff08\u8bd5\u7528\uff09 \u6309\u94ae\u6765\u5c1d\u8bd5\u8fd9\u4e9b\u4f5c\u65b9\u6cd5\u4e2d\u7684\u6bcf\u4e00\u79cd\u3002<\/p>\n<p>So, let\u2019s try it with the \/api\/companies action:<br \/>\n\u90a3\u4e48\uff0c\u8ba9\u6211\u4eec\u7528 \/api\/companies\u4f5c\u6765\u8bd5\u8bd5\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3003.jpg\" alt=\"alt text\" \/><\/p>\n<p>Once we click the Execute button, we are going to see that we get our response:<br \/>\n\u5355\u51fb Execute \u6309\u94ae\u540e\uff0c\u6211\u4eec\u5c06\u770b\u5230\u6211\u4eec\u6536\u5230\u4e86\u54cd\u5e94\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3004.jpg\" alt=\"alt text\" \/><\/p>\n<p>And this is an expected response. We are not authorized. To enable authorization, we have to add some modifications.<br \/>\n\u8fd9\u662f\u610f\u6599\u4e4b\u4e2d\u7684\u56de\u5e94\u3002\u6211\u4eec\u6ca1\u6709\u83b7\u5f97\u6388\u6743\u3002\u8981\u542f\u7528\u6388\u6743\uff0c\u6211\u4eec\u5fc5\u987b\u6dfb\u52a0\u4e00\u4e9b\u4fee\u6539\u3002<\/p>\n<h2>30.3 Adding Authorization Support<\/h2>\n<p>30.3 \u6dfb\u52a0\u6388\u6743\u652f\u6301<\/p>\n<p>To add authorization support, we need to modify the ConfigureSwagger\u200c method:<br \/>\n\u8981\u6dfb\u52a0\u6388\u6743\u652f\u6301\uff0c\u6211\u4eec\u9700\u8981\u4fee\u6539 ConfigureSwagger \u65b9\u6cd5\uff1a<\/p>\n<pre><code>public static void ConfigureSwagger(this IServiceCollection services) { services.AddSwaggerGen(s =&gt; { s.SwaggerDoc(&quot;v1&quot;, new OpenApiInfo { Title = &quot;Code Maze API&quot;, Version = &quot;v1&quot; }); s.SwaggerDoc(&quot;v2&quot;, new OpenApiInfo { Title = &quot;Code Maze API&quot;, Version = &quot;v2&quot; }); s.AddSecurityDefinition(&quot;Bearer&quot;, new OpenApiSecurityScheme { In = ParameterLocation.Header, Description = &quot;Place to add JWT with Bearer&quot;, Name = &quot;Authorization&quot;, Type = SecuritySchemeType.ApiKey, Scheme = &quot;Bearer&quot; }); s.AddSecurityRequirement(new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = &quot;Bearer&quot;}, Name = &quot;Bearer&quot;, }, new List&lt;string&gt;() } }); }); }\n<\/code><\/pre>\n<p>With this modification, we are adding the security definition in our swagger configuration. Now, we can start our app again and navigate to the index.html page.<br \/>\n\u901a\u8fc7\u6b64\u4fee\u6539\uff0c\u6211\u4eec\u5c06\u5728 swagger \u914d\u7f6e\u4e2d\u6dfb\u52a0\u5b89\u5168\u5b9a\u4e49\u3002\u73b0\u5728\uff0c\u6211\u4eec\u53ef\u4ee5\u518d\u6b21\u542f\u52a8\u6211\u4eec\u7684\u5e94\u7528\u7a0b\u5e8f\u5e76\u5bfc\u822a\u5230 index.html \u9875\u9762\u3002<\/p>\n<p>The first thing we are going to notice is the Authorize options for requests:<br \/>\n\u6211\u4eec\u9996\u5148\u8981\u6ce8\u610f\u7684\u662f\u8bf7\u6c42\u7684 Authorize \u9009\u9879\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3005.jpg\" alt=\"alt text\" \/><\/p>\n<p>We are going to use that in a moment. But let\u2019s get our token first. For that, let\u2019s open the api\/authentication\/login action, click try it out, add credentials, and copy the received token:<br \/>\n\u6211\u4eec\u7a0d\u540e\u4f1a\u7528\u5230\u5b83\u3002\u4f46\u662f\uff0c\u8ba9\u6211\u4eec\u5148\u83b7\u53d6\u6211\u4eec\u7684\u4ee4\u724c\u3002\u4e3a\u6b64\uff0c\u8ba9\u6211\u4eec\u6253\u5f00 api\/authentication\/login\u4f5c\uff0c\u5355\u51fb try it out\uff0c\u6dfb\u52a0\u51ed\u636e\uff0c\u7136\u540e\u590d\u5236\u6536\u5230\u7684\u4ee4\u724c\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3006.png\" alt=\"alt text\" \/><\/p>\n<p>Once we have copied the token, we are going to click on the authorization button for the \/api\/companies request, paste it with the Bearer in front of it, and click Authorize:<br \/>\n\u590d\u5236\u4ee4\u724c\u540e\uff0c\u6211\u4eec\u5c06\u5355\u51fb \/api\/companies \u8bf7\u6c42\u7684\u6388\u6743\u6309\u94ae\uff0c\u5c06\u5176\u7c98\u8d34\u5230\u5176\u524d\u9762\u5e76\u5e26\u6709 Bearer\uff0c\u7136\u540e\u5355\u51fb Authorize\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3007.jpg\" alt=\"alt text\" \/><\/p>\n<p>After authorization, we are going to click on the Close button and try our request:<br \/>\n\u6388\u6743\u540e\uff0c\u6211\u4eec\u5c06\u5355\u51fb Close \u6309\u94ae\u5e76\u5c1d\u8bd5\u6211\u4eec\u7684\u8bf7\u6c42\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3008.jpg\" alt=\"alt text\" \/><\/p>\n<p>And we get our response. Excellent job.<br \/>\n\u6211\u4eec\u5f97\u5230\u4e86\u6211\u4eec\u7684\u56de\u5e94\u3002\u5e72\u5f97\u597d\u3002<\/p>\n<h2>\u300030.4 Extending Swagger Configuration<\/h2>\n<p>30.4 \u6269\u5c55 Swagger \u914d\u7f6e<\/p>\n<p>Swagger provides options for extending the documentation and customizing the UI. Let\u2019s explore some of those.\u200c<br \/>\nSwagger \u63d0\u4f9b\u4e86\u7528\u4e8e\u6269\u5c55\u6587\u6863\u548c\u81ea\u5b9a\u4e49 UI \u7684\u9009\u9879\u3002\u8ba9\u6211\u4eec\u6765\u63a2\u8ba8\u5176\u4e2d\u7684\u4e00\u4e9b\u3002<\/p>\n<p>First, let\u2019s see how we can specify the API info and description. The configuration action passed to the AddSwaggerGen() method adds information such as Contact, License, and Description. Let\u2019s provide some values for those:<br \/>\n\u9996\u5148\uff0c\u8ba9\u6211\u4eec\u770b\u770b\u5982\u4f55\u6307\u5b9a API \u4fe1\u606f\u548c\u63cf\u8ff0\u3002\u4f20\u9012\u7ed9 AddSwaggerGen\uff08\uff09 \u65b9\u6cd5\u7684\u914d\u7f6e\u4f5c\u5c06\u6dfb\u52a0 Contact\u3001License \u548c Description \u7b49\u4fe1\u606f\u3002\u8ba9\u6211\u4eec\u4e3a\u8fd9\u4e9b\u503c\u63d0\u4f9b\u4e00\u4e9b\u503c\uff1a<\/p>\n<pre><code>s.SwaggerDoc(&quot;v1&quot;, new OpenApiInfo { Title = &quot;Code Maze API&quot;, Version = &quot;v1&quot;, Description = &quot;CompanyEmployees API by CodeMaze&quot;, TermsOfService = new Uri(&quot;https:\/\/example.com\/terms&quot;), Contact = new OpenApiContact { Name = &quot;John Doe&quot;, Email = &quot;John.Doe@gmail.com&quot;, Url = new Uri(&quot;https:\/\/twitter.com\/johndoe&quot;), }, License = new OpenApiLicense { Name = &quot;CompanyEmployees API LICX&quot;, Url = new Uri(&quot;https:\/\/example.com\/license&quot;), } });\n......<\/code><\/pre>\n<p>We have implemented this just for the first version, but you get the point. Now, let\u2019s run the application once again and explore the Swagger UI:<br \/>\n\u6211\u4eec\u53ea\u4e3a\u7b2c\u4e00\u4e2a\u7248\u672c\u5b9e\u73b0\u4e86\u8fd9\u4e00\u70b9\uff0c\u4f46\u60a8\u660e\u767d\u4e86\u3002\u73b0\u5728\uff0c\u8ba9\u6211\u4eec\u518d\u6b21\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u5e76\u63a2\u7d22 Swagger UI\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3009.jpg\" alt=\"alt text\" \/><\/p>\n<p>For enabling XML comments, we need to suppress warning 1591, which will now give warnings about any method, class, or field that doesn\u2019t have triple-slash comments. We need to do this in the Presentation project.<br \/>\n\u8981\u542f\u7528 XML \u6ce8\u91ca\uff0c\u6211\u4eec\u9700\u8981\u7981\u6b62\u663e\u793a\u8b66\u544a 1591\uff0c\u5b83\u73b0\u5728\u5c06\u9488\u5bf9\u4efb\u4f55\u6ca1\u6709\u4e09\u659c\u6760\u6ce8\u91ca\u7684\u65b9\u6cd5\u3001\u7c7b\u6216\u5b57\u6bb5\u53d1\u51fa\u8b66\u544a\u3002\u6211\u4eec\u9700\u8981\u5728 Presentation \u9879\u76ee\u4e2d\u6267\u884c\u6b64\u4f5c\u3002<\/p>\n<p>Additionally, we have to add the documentation path for the same project, since our controllers are in the Presentation project:<br \/>\n\u6b64\u5916\uff0c\u6211\u4eec\u5fc5\u987b\u4e3a\u540c\u4e00\u9879\u76ee\u6dfb\u52a0\u6587\u6863\u8def\u5f84\uff0c\u56e0\u4e3a\u6211\u4eec\u7684\u63a7\u5236\u5668\u4f4d\u4e8e Presentation \u9879\u76ee\u4e2d\uff1a<\/p>\n<pre><code>&lt;Project Sdk=&quot;Microsoft.NET.Sdk&quot;&gt; &lt;PropertyGroup&gt; &lt;TargetFramework&gt;net6.0&lt;\/TargetFramework&gt; &lt;ImplicitUsings&gt;enable&lt;\/ImplicitUsings&gt; &lt;Nullable&gt;enable&lt;\/Nullable&gt; &lt;\/PropertyGroup&gt; &lt;PropertyGroup Condition=&quot;&#039;$(Configuration)|$(Platform)&#039;==&#039;Debug|AnyCPU&#039;&quot;&gt; &lt;DocumentationFile&gt;CompanyEmployees.Presentation.xml&lt;\/DocumentationFile&gt; &lt;OutputPath&gt;&lt;\/OutputPath&gt; &lt;NoWarn&gt;1701;1702;1591&lt;\/NoWarn&gt; &lt;\/PropertyGroup&gt; &lt;PropertyGroup Condition=&quot;&#039;$(Configuration)|$(Platform)&#039;==&#039;Release|AnyCPU&#039;&quot;&gt; &lt;NoWarn&gt;1701;1702;1591&lt;\/NoWarn&gt; &lt;\/PropertyGroup&gt;<\/code><\/pre>\n<p>Now, let\u2019s modify our configuration:<br \/>\n\u73b0\u5728\uff0c\u8ba9\u6211\u4eec\u4fee\u6539\u6211\u4eec\u7684\u914d\u7f6e\uff1a<\/p>\n<pre><code>s.SwaggerDoc(&quot;v2&quot;, new OpenApiInfo { Title = &quot;Code Maze API&quot;, Version = &quot;v2&quot; }); var xmlFile = $&quot;{typeof(Presentation.AssemblyReference).Assembly.GetName().Name}.xml&quot;; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); s.IncludeXmlComments(xmlPath);<\/code><\/pre>\n<p>Next, adding triple-slash comments to the action method enhances the Swagger UI by adding a description to the section header:<br \/>\n\u63a5\u4e0b\u6765\uff0c\u901a\u8fc7\u5411\u90e8\u5206\u6807\u9898\u6dfb\u52a0\u8bf4\u660e\uff0c\u5411\u4f5c\u65b9\u6cd5\u6dfb\u52a0\u4e09\u659c\u6760\u6ce8\u91ca\u53ef\u589e\u5f3a Swagger UI\uff1a<\/p>\n<pre><code>\/\/\/ &lt;summary&gt; \/\/\/ Gets the list of all companies \/\/\/ &lt;\/summary&gt; \/\/\/ &lt;returns&gt;The companies list&lt;\/returns&gt; [HttpGet(Name = &quot;GetCompanies&quot;)] [Authorize(Roles = &quot;Manager&quot;)] public async Task&lt;IActionResult&gt; GetCompanies()<\/code><\/pre>\n<p>And this is the result:<br \/>\n\u7ed3\u679c\u5982\u4e0b\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3010.jpg\" alt=\"alt text\" \/><\/p>\n<p>The developers who consume our APIs are usually more interested in what it returns \u2014 specifically the response types and error codes. Hence, it is very important to describe our response types. These are denoted using XML comments and data annotations.<br \/>\n\u4f7f\u7528\u6211\u4eec\u7684 API \u7684\u5f00\u53d1\u4eba\u5458\u901a\u5e38\u5bf9\u5b83\u8fd4\u56de\u7684\u5185\u5bb9\u66f4\u611f\u5174\u8da3 \u2014 \u7279\u522b\u662f\u54cd\u5e94\u7c7b\u578b\u548c\u9519\u8bef\u4ee3\u7801\u3002\u56e0\u6b64\uff0c\u63cf\u8ff0\u6211\u4eec\u7684\u54cd\u5e94\u7c7b\u578b\u975e\u5e38\u91cd\u8981\u3002\u8fd9\u4e9b\u4f7f\u7528 XML \u6ce8\u91ca\u548c\u6570\u636e\u6ce8\u91ca\u8868\u793a\u3002<\/p>\n<p>Let\u2019s enhance the response types a little bit:<br \/>\n\u8ba9\u6211\u4eec\u7a0d\u5fae\u589e\u5f3a\u4e00\u4e0b\u54cd\u5e94\u7c7b\u578b\uff1a<\/p>\n<pre><code>\/\/\/ &lt;summary&gt; \/\/\/ Creates a newly created company \/\/\/ &lt;\/summary&gt; \/\/\/ &lt;param name=&quot;company&quot;&gt;&lt;\/param&gt; \/\/\/ &lt;returns&gt;A newly created company&lt;\/returns&gt; \/\/\/ &lt;response code=&quot;201&quot;&gt;Returns the newly created item&lt;\/response&gt; \/\/\/ &lt;response code=&quot;400&quot;&gt;If the item is null&lt;\/response&gt; \/\/\/ &lt;response code=&quot;422&quot;&gt;If the model is invalid&lt;\/response&gt; [HttpPost(Name = &quot;CreateCompany&quot;)] [ProducesResponseType(201)] [ProducesResponseType(400)] [ProducesResponseType(422)]<\/code><\/pre>\n<p>Here, we are using both XML comments and data annotation attributes. Now, we can see the result:<br \/>\n\u5728\u8fd9\u91cc\uff0c\u6211\u4eec\u540c\u65f6\u4f7f\u7528\u4e86 XML \u6ce8\u91ca\u548c\u6570\u636e\u6ce8\u91ca\u5c5e\u6027\u3002\u73b0\u5728\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u7ed3\u679c\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3011.jpg\" alt=\"alt text\" \/><\/p>\n<p>And, if we inspect the response part, we will find our mentioned responses:<br \/>\n\u800c\u4e14\uff0c\u5982\u679c\u6211\u4eec\u68c0\u67e5\u54cd\u5e94\u90e8\u5206\uff0c\u6211\u4eec\u4f1a\u627e\u5230\u6211\u4eec\u63d0\u5230\u7684\u54cd\u5e94\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/3012.jpg\" alt=\"alt text\" \/><\/p>\n<p>Excellent.We can continue to the deployment part.<br \/>\n\u975e\u5e38\u597d\u3002\u6211\u4eec\u53ef\u4ee5\u7ee7\u7eed\u8fdb\u884c\u90e8\u7f72\u90e8\u5206\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>30 DOCUMENTING API WITH SWAGGER 30 \u4f7f\u7528 SWAGGER \u7f16\u5199 API \u6587\u6863 Developers who consume our API might be trying to solve important business problems with it. Hence, it is very important for them to understand how to use our API effectively. This is where API documentation comes into the picture.\u200c \u4f7f\u7528\u6211\u4eec\u7684 API \u7684\u5f00\u53d1\u4eba\u5458\u53ef\u80fd\u6b63\u5728\u5c1d\u8bd5\u4f7f\u7528\u5b83\u6765\u89e3\u51b3\u91cd\u8981\u7684\u4e1a\u52a1\u95ee\u9898\u3002\u56e0\u6b64\uff0c\u4ed6\u4eec\u4e86\u89e3\u5982\u4f55\u6709\u6548\u5730\u4f7f\u7528\u6211\u4eec\u7684 API \u975e\u5e38\u91cd\u8981\u3002\u8fd9\u5c31\u662f [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1158","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/1158","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1158"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/1158\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1158"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1158"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1158"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}