自定义 swagger ui 以显示参数架构

customize swagger ui to show parameter schema

我有一个 swashbuckle swaggergen UI 输出,看起来像: [![提出请求][1]][1]

并且(由于某些原因),我不想使用典型的验证属性,而是在请求正文中进行验证。我的容器名称是一个 Azure Blob 存储容器,因此它必须是 3-63 个字符并匹配一个简单的正则表达式(没有大写字母,基本上是字母数字)。

我想修改 UI 以也显示这些要求...因此,我编写了一个 OperationFilter 和 Attribute。我假设我想修改 SwaggerParameters,然后我注意到一个方便的模式,其中包含 "MinLength"、"MaxLength" 和 "Pattern" 等参数——换句话说,正是我想要显示的内容我的 UI。所以我修改了那个。这是输出:

      "put": {
        "tags": [
          "Values"
        ],
        "summary": "API Operation – Create & Update\r\n::\r\nCreates a new content file entry in the containername provided.",
        "description": "If the container name has the word public in it, then the container\r\nshall be public otherwise the container, identified by the\r\ncontainername, shall be private. If the file, identified by the\r\nfilename parameter on the URI, already exists then the existing blob\r\nentry will be overwritten with the new fileData uploaded.",
        "operationId": "Put",
        "parameters": [
          {
            "name": "containername",
            "in": "path",
            "description": "The container the file resides in.",
            "required": true,
            "schema": {
              "maxLength": 63,
              "minLength": 3,
              "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
              "type": "string"
            }
          },
          {
            "name": "fileName",
            "in": "path",
            "description": "The name of the file uploaded. This shall become the block blob Id.",
            "required": true,
            "schema": {
              "maxLength": 75,
              "minLength": 1,
              "pattern": "\S",
              "type": "string"
            }
          }
        ],

问题是,UI 看起来一样。我应该修改哪些内容才能呈现这些值?

执行此操作的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using static Foo.SwaggerParameterDescriptions;

namespace Foo
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class SwaggerPathParameterDescriptions : Attribute
    {
        public enum Description
        {
            Default,
            MinLength,
            MaxLength,
            Pattern
        }

        public string ParameterName { get; set; }
        public Dictionary<Description, dynamic> Settings { get; set; }

        public SwaggerPathParameterDescriptions(string parameterName, string json)
        {
            Dictionary<string, dynamic> dict = JsonSerializer
                .Deserialize<Dictionary<string, dynamic>>(json);

            Dictionary<Description, dynamic> settings = dict.Entries()
                       .ToDictionary(entry => (Description)Enum.Parse(typeof(Description), (string)entry.Key),
                                     entry => entry.Value);

            ParameterName = parameterName;
            Settings = settings;
        }

        public IEnumerable<SwaggerParameterSchemaDescription> GetSwaggerParameters()
        {
            return Settings.Keys.Select(key =>
                new SwaggerParameterSchemaDescription { ParameterName = key, Value = Settings[key] });
        }
    }

    public class SwaggerParameterSchemaDescription
    {
        public Description ParameterName { get; set; }
        public dynamic Value { get; set; }

        public void ApplyTo(OpenApiParameter param)
        {
            string representation = $"{Value}";
            switch (ParameterName)
            {
                case Description.Default:
                    param.Schema.Default = new OpenApiString(representation); // Path Parameters must be strings!
                    break;
                case Description.MinLength:
                    param.Schema.MinLength = Int32.Parse(representation);
                    break;
                case Description.MaxLength:
                    param.Schema.MaxLength = Int32.Parse(representation);
                    break;
                case Description.Pattern:
                    param.Schema.Pattern = representation;
                    break;
                default:
                    throw new InvalidOperationException();
            }
        }
    }

    public class AddSettings : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            foreach (var param in operation.Parameters)
            {
                var actionParam = context.ApiDescription.ActionDescriptor.Parameters.First(p => p.Name == param.Name);
                if (actionParam != null)
                {
                    context.MethodInfo
                        .GetCustomAttributes(true)
                        .OfType<SwaggerPathParameterDescriptions>()
                        .Where(p => p.ParameterName == param.Name)
                        .ToList()
                        .ForEach(customAttribute =>
                    {
                        foreach (SwaggerParameterSchemaDescription description in customAttribute.GetSwaggerParameters())
                        {
                            description.ApplyTo(param);
                        }
                    });
                }

            }
        }
    }
}

并在启动中:

services.AddSwaggerGen(c => {
                c.OperationFilter<AddSettings>();

然后像这样使用:

        [HttpPut("{containername}/contentfiles/{fileName}")]
        [SwaggerPathParameterDescriptions("containername", "{\"MinLength\":3,\"MaxLength\":63,\"Pattern\":\"^[a-z0-9]+(-[a-z0-9]+)*$\"}")]
        [SwaggerPathParameterDescriptions("fileName", "{\"MinLength\":1,\"MaxLength\":75,\"Pattern\":\"\\S\"}")]
        [SwaggerResponseHeader(StatusCodes.Status201Created, "Location", "string", "Location of the newly created resource")]
        [ProducesResponseType(StatusCodes.Status201Created)]
        [ProducesResponseType(StatusCodes.Status204NoContent)]
        [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
        [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status503ServiceUnavailable)]
        public ActionResult Put(string containername, string fileName, IFormFile fileData)

我的问题是它没有呈现。 :( 我还有更多工作要做?还是我修改了错误的值?

Swagger UI 仅在配置时显示参数 minLengthmaxLengthpattern option. 显示如何通过 Swashbuckle 配置启用此选项.

但是,您必须等待 Swagger UI 的下一个版本才能使 showCommonExtensions: true 选项适用于 OpenAPI 3.0 定义。代码在 Swagger UI repositorymaster 分支中,但尚未发布新版本。如果需要,您可以从 master 分支自己构建 Swagger UI,并在您的项目中使用生成的 dist 资产立即获得此功能。