Open gturri opened 1 year ago
FWIW (in case someone has the same issue and stumble on this feature request), I found a workaround, which is in a nutshell:
OpenApiDocument
to a yaml stringDictionary
with YamlDotNet
Dictionary
Dictionary
to get the file I was looking for.From a code point of view it looks like this:
var oas = ...
// Ensure the schemas are sorted. This can be done directly on the OpenApiDocument
oas.Components.Schemas = new SortedList<string, OpenApiSchema>(oas.Components.Schemas, StringComparer.OrdinalIgnoreCase);
// Now the trick to sort the paths
using var oasWriter = new StringWriter();
oas.SerializeAsV3(new OpenApiYamlWriter(oasWriter));
var yamlDoc = (Dictionary<object, object>) new YamlDotNet.Serialization.Deserializer().Deserialize(new StringReader(oasWriter.ToString()));
yamlDoc["paths"] = ToDictionaryWithSortedKeyStrings((Dictionary<object, object>) yamlDoc["paths"]);
// Now I can serialize back (with YamlDotNet this time)
using var textWriter = new StreamWriter(outPath);
new YamlDotNet.Serialization.Serializer().Serialize(textWriter, yamlDoc);
// A trick here is that we get a IDictionary<object, object> but we know that the keys are string, and we need to
// cast them in order to apply a deterministic order to it (because if I don't use StringComparer.OrdinalIgnoreCase
// I may end up with a different behavior on my laptop and on my CI
private static SortedList<string, object> ToDictionaryWithSortedKeyStrings(IDictionary<object, object> dictionary)
{
var sorted = new SortedList<string, object>(StringComparer.OrdinalIgnoreCase);
foreach (var kvp in dictionary)
{
sorted.Add(kvp.Key.ToString(), kvp.Value);
}
return sorted;
}
That being said, I guess it makes sense to leave this feature request open, because it would be much more convenient if this could be supported directly by OpenAPI.NET
Is your feature request related to a problem? Please describe. I use OpenAPI.NET to serialize instances of
OpenApiDocument
and store them in a git repo. So, ideally I would like that when I make a simple change to my API, I get a simple change in the serialized document, in order to have an easy to review git diff.It is not the case currently, because serialization iterates on some
Dictionary
and that the order of the iteration is hence not deterministic. For instance, if I add one endpoint to my API, I would like that my serialized OAS file looks like what it was at my previous generation, with just a few added lines. But in practice I may have more diffs, because my paths and my schemas may end up serialized in a different order.Describe the solution you'd like I can already achieve part of what I would like from my client code in the sense that I can get a deterministic order for the Schemas section, if I do
It works rather fine, in the sense that it leads to a serialized
schemas
section where all schemas are order alphabetically (making it nice for my git diffs, and making the file easier to browse overall). However, it does not feel really "clean" in itself, and this approach does not work for other parts of the document. In particular for the paths; because they are represented by anOpenApiPaths
which ends up extending aDictionary
and I could not find a virtual method or an attribute I could override to achieve a similar deterministic order.Given this context, a solution that would be nice would be to edit
IOpenApiSerializable
in order to turnSerializeAsV3(IOpenApiWriter writer)
intoSerializeAsV3(IOpenApiWriter writer, bool enforceAlphabeticalOrder = false)
. So for instanceOpenApiExtensibleDictionary.SerializeAsV3
could be implemented likeHaving this feature behind a boolean
enforceAlphabeticalOrder
could make it possible for users interested in this feature to use it, and users not interested in it would not suffer any performance penalty by leaving it to false.Describe alternatives you've considered As explained above, I tried to achieve this order from my client code, but faced some hard limitations
Additional context If the proposed approach looks good to you, and if it could help, I guess I could try to propose a pull request to implement this.