从大型 OpenAPI 文档或使用 NewtonSoft 获取 JSON 模式并解析引用

Get the JSON Schema's from a large OpenAPI Document OR using NewtonSoft and resolve refs

我目前正在寻找从大型 OpenAPI 规范中提取所有 JSON 模式。我一直在使用以下 NuGet 包:

Microsoft.OpenApi v1.3.1 Microsoft.OpenApi.Readers v1.3.1

我希望使用这些来解析大型 Open API 规范并提取所有 JSON 模式,我能够将其解析为 'Microsoft.OpenApi.Models.OpenApiSchema' 对象。但我似乎无法从这些对象创建 JSON 架构并将其写入文件。

目前我有以下情况:

using (FileStream fs = File.Open(file.FullName, FileMode.Open))
{
    var openApiDocument = new OpenApiStreamReader().Read(fs, out var diagnostic);
    foreach (var schema in openApiDocument.Components.Schemas)
    {
        var schemaName = schema.Key;
        var schemaContent = schema.Value;

        var outputDir = Path.Combine(outputDirectory.FullName, fileNameWithoutExtension);
        if (!Directory.Exists(outputDir))
        {
            Directory.CreateDirectory(outputDir);
        }
        var outputPath = Path.Combine(outputDir, schemaName + "-Schema.json");
        var outputString = schemaContent.Serialize(OpenApiSpecVersion.OpenApi3_0, OpenApiFormat.Json);
        using (TextWriter sw = new StreamWriter(outputPath, true))
        {
            sw.Write(outputString);
            sw.Close();
        }
    }
}

schemaContent 似乎具有架构的所有相关属性,但我似乎无法确定将它从该对象获取到 JSON 的下一步模式。我确定我遗漏了一些简单的东西,所以任何见解都将不胜感激。

已更新

我想了想,采用了稍微不同的方法,改用 NewtonSoft Json。

var OpenApitext = File.ReadAllText(file.FullName, Encoding.UTF8);
var settings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    MetadataPropertyHandling = MetadataPropertyHandling.Ignore, //ign
    Formatting = Newtonsoft.Json.Formatting.Indented
};

dynamic openApiJson = JsonConvert.DeserializeObject<ExpandoObject>(OpenApitext, settings);

if (openApiJson?.components?.schemas != null)
{
    foreach (var schema in openApiJson.components.schemas)
    {
        var schemaString = JsonConvert.SerializeObject(schema, settings);

        var outputDir = Path.Combine(outputDirectory.FullName, fileNameWithoutExtension);
        if (!Directory.Exists(outputDir))
        {
            Directory.CreateDirectory(outputDir);
        }
        var outputPath = Path.Combine(outputDir, schema.Name + "-Schema.json");

        using (TextWriter sw = new StreamWriter(outputPath, true))
        {
            sw.Write(schemaString);
            sw.Close();
        }
    }
}

现在这将允许我创建 JSON 架构并将其写入文件,但它不想解析引用。查看 API 规范,所有引用似乎都是 API 规范的本地引用。在循环浏览模式并将它们写入文件之前,我需要做什么才能解析 Open API 规范中的所有引用?我做了一些研究,有些人似乎自己构建了此功能,但他们总是使用 class 对象作为支持它的方式,我在这里无法做到这一点。

我最终通过 microsoft/OpenAPI.NET GitHub 存储库联系到了我。通过 coincidence/happenstance 我从那里和这里得到了同一个人的回复。所以,谢谢 Darrel,你帮助我解决了上述让我相当困惑的场景。最后我知道是我没有完全正确地实现它。

作为参考,下面的用例是采用相当大的 OpenAPI 规范 (Json) 并提取引用的 JSON 模式,同时确保 JSON 指针 ($ref, $id) 等在写入文件时得到解决。

我想采用这种方法的原因是,由于 OpenAPI 规范的规模,我必须使用它来使用 pre-built 工具(例如可以提取模式的 Postman)非常困难。

我实现的最终代码片段,有几行有点粗糙,我会在周末整理一下。

Console.WriteLine($"Processing file: {file.FullName}");
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file.FullName);
var fileExtension = Path.GetExtension(file.FullName);

var reader = new OpenApiStreamReader();
var result = await reader.ReadAsync(new FileStream(file.FullName, FileMode.Open));

foreach (var schemaEntry in result.OpenApiDocument.Components.Schemas)
{
    var schemaFileName = schemaEntry.Key + ".json";
    Console.WriteLine("Creating " + schemaFileName);

    var outputDir = Path.Combine(outputDirectory.FullName, fileNameWithoutExtension);
    if (!Directory.Exists(outputDir))
    {
        Directory.CreateDirectory(outputDir);
    }
    var outputPath = Path.Combine(outputDir, schemaFileName + "-Schema.json");

    using FileStream? fileStream = new FileStream(outputPath, FileMode.CreateNew);
    var writerSettings = new OpenApiWriterSettings() { InlineLocalReferences = true, InlineExternalReferences = true };
    using var writer = new StreamWriter(fileStream);
    schemaEntry.Value.SerializeAsV2WithoutReference(new OpenApiJsonWriter(writer, writerSettings));
}