示例请求正文中 JsonPatchDocument 的 Swagger 意外 API PATCH 操作文档

问题描述 投票:0回答:2

我正在制作 Core 3.1 Web API 并使用 JsonPatch 创建 PATCH 操作。我有一个名为

Patch
的操作,它有一个
JsonPatchDocument
参数。这是该操作的签名:

[HttpPatch("{id}")]
public ActionResult<FileRecordDto> Patch(int id, [FromBody] JsonPatchDocument<FileRecordQueryParams> patchDoc)

据我了解,参数需要接收以下结构的 JSON 数据,我已经使用该操作成功测试了该数据:

[
  {
    "op": "operationName",
    "path": "/propertyName",
    "value": "newPropertyValue"
  }
]

但是,Swagger 生成的操作文档具有不同的结构:

我不熟悉这个结构,甚至其中缺少

"value"
属性,而
JsonPatchDocument
对象具有该属性。我见过的每个使用
replace
操作进行修补的示例都具有第一个结构。

为什么 Swagger 为 PATCH 端点的请求正文中的

JsonPatchDocument
对象生成替代结构?我该如何解决这个问题?

为 Swagger 安装的 NuGet 包:

c# asp.net-core asp.net-web-api swagger swashbuckle
2个回答
13
投票

Swashbuckle.AspNetCore
无法与此类型正常工作
JsonPatchDocument<UpdateModel>
,这不代表预期的补丁请求文档。

您需要自定义文档过滤器来修改生成的规范。

public class JsonPatchDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        var schemas = swaggerDoc.Components.Schemas.ToList();
        foreach (var item in schemas)
        {
            if (item.Key.StartsWith("Operation") || item.Key.StartsWith("JsonPatchDocument"))
                swaggerDoc.Components.Schemas.Remove(item.Key);
        }

        swaggerDoc.Components.Schemas.Add("Operation", new OpenApiSchema
        {
            Type = "object",
            Properties = new Dictionary<string, OpenApiSchema>
            {
                {"op", new OpenApiSchema{ Type = "string" } },
                {"value", new OpenApiSchema{ Type = "string"} },
                {"path", new OpenApiSchema{ Type = "string" } }
            }
        });

        swaggerDoc.Components.Schemas.Add("JsonPatchDocument", new OpenApiSchema
        {
            Type = "array",
            Items = new OpenApiSchema
            {
                Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Operation" }
            },
            Description = "Array of operations to perform"
        });

        foreach (var path in swaggerDoc.Paths.SelectMany(p => p.Value.Operations)
        .Where(p => p.Key == Microsoft.OpenApi.Models.OperationType.Patch))
        {
            foreach (var item in path.Value.RequestBody.Content.Where(c => c.Key != "application/json-patch+json"))
                path.Value.RequestBody.Content.Remove(item.Key);
            var response = path.Value.RequestBody.Content.Single(c => c.Key == "application/json-patch+json");
            response.Value.Schema = new OpenApiSchema
            {
                Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "JsonPatchDocument" }
            };
        }
    }
}

注册过滤器:

services.AddSwaggerGen(c => c.DocumentFilter<JsonPatchDocumentFilter>());

结果:


0
投票

这是处理模式和路径的

OpenAPI3
OAS3
- 新的
SwaggerUI
版本)的更新代码。

public class JsonPatchDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        // Handle schemas
        var keysToRemove = swaggerDoc.Components.Schemas
            .Where(s => s.Key.Contains("SystemTextJsonPatch", StringComparison.OrdinalIgnoreCase) || s.Key.Contains("JsonPatchDocument", StringComparison.OrdinalIgnoreCase))
            .Select(s => s.Key)
            .ToList();

        foreach (var key in keysToRemove)
        {
            swaggerDoc.Components.Schemas.Remove(key);
        }

        swaggerDoc.Components.Schemas.Add("JsonPatchDocument", new OpenApiSchema
        {
            Type = "object",
            Description = "Describes a single operation in a JSON Patch document. Includes the operation type, the target property path, and the value to be used.",
            Properties = new Dictionary<string, OpenApiSchema>
            {
                {
                    "op", new OpenApiSchema
                    {
                        Type = "string",
                        Description = "The operation type. Allowed values: 'add', 'remove', 'replace', 'move', 'copy', 'test'.",
                    }
                },
                {
                    "path", new OpenApiSchema
                    {
                        Type = "string",
                        Description = "The JSON Pointer path to the property in the target document where the operation is to be applied.",
                    }
                },
                {
                    "value", new OpenApiSchema
                    {
                        Type = "string",
                        Description = "The value to apply for 'add', 'replace', or 'test' operations. Not required for 'remove', 'move', or 'copy'.",
                    }
                },
            },
        });

        // Handle paths
        foreach (var path in swaggerDoc.Paths)
        {
            if (path.Value.Operations.TryGetValue(OperationType.Patch, out var patchOperation) && patchOperation.RequestBody != null)
            {
                foreach (var key in patchOperation.RequestBody.Content.Keys)
                {
                    patchOperation.RequestBody.Content.Remove(key);
                }

                if (patchOperation.OperationId.StartsWith("odata", StringComparison.OrdinalIgnoreCase))
                {
                    path.Value.Operations.Remove(OperationType.Patch);
                }

                patchOperation.RequestBody.Content.Add("application/json-patch+json", new OpenApiMediaType
                {
                    Schema = new OpenApiSchema
                    {
                        Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "JsonPatchDocument" },
                    },
                });
            }
        }
    }
}

以前的用户界面:

/oauth/
有条目:

并且

schemas
看起来像:

说明:

当前版本是:

请记住更改

Name
属性的
HttpPatch
并保留
JsonPatchDocument
架构名称。

© www.soinside.com 2019 - 2024. All rights reserved.