Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get OpenApi Generator to convert Dictionary<int, string> correctly?

Right now my Api returns a model with a Dictionary<int, string> property in it:

public Dictionary<int, string> Subdivisions { get; set; }

When I run OpenApi Generator, the output class has

public Dictionary<string, string> Subdivisions { get; set; }

I know the JSON spec doesn't allow integer keys, but this really screws up consumers of that API which are expecting <int, string>.

What can I do to ensure my output class has Dictionary<int, string> instead of Dictionary<string, string>?

like image 874
DaveDev Avatar asked May 12 '21 01:05

DaveDev


1 Answers

Since Swagger/OpenAPI definitions are specific to REST, they will likely continue to support models that can be expressed in JSON. JSON is a language-agnostic serialization format that supports objects and collections, but it has no methods or actual implementation. REST provides the methods to mutate the server's copy of the JSON, and the consumer is then required to interpret the response as needed. Since there is no Map in JSON, the default for an IDictionary is to serialize it as an object using it's keys as property names--the benefit is the map-like lookup function but the cost is that property names have to be strings.

So, what would a Dictionary<int,string> look like in valid JSON? With a custom serializer and deserializer we could expect a list of Key-Value-Pair objects:

[
    {"key":1, "value": "one"},
    {"key":2, "value": "two"}
]

You would publish the REST operation with this KVP model, then you would put a custom converter on your API to convert this list of KVPs to and from a Dictionary. This would be conformant to OAS/JSON and allow non-REST consumers of that API/service which are expecting <int, string>. There are several examples of how to do this:

C# JSON custom serialization https://www.newtonsoft.com/json/help/html/SerializingCollections.htm

However, if you REALLY need to generate code from a swagger definition that doesn't conform to the standard, it is possible to overwrite the generator to meet your needs. Consider it a warning that your implementation is against-the-grain, and all the effort you put into this codegen may be undone by minor releases. It's better to find a way to go in the direction of the community for the longest viability of your solution.

With that said, the generator is a simple Java program that reads the spec and outputs text files using Mustache templates. The "CodeGen" classes parse the spec into arrays following the language specific logic, then the "Mustache" templates are applied logic-less over the arrays to generate code. By reading the Java as a guide, I am usually able to generate my custom classes by modifying only the Mustache templates or the configuration. Unfortunately for your case, the returnType for an Operation only supports List or primitive, so the CodeGen Java would need to be modified if you want an API generated to return a Dictionary. Be sure to bring a paddle if you go this far up stream!

Here is where the IDictonary type is set for Maps. Here is where it is set generically, and here is for C#. This is the Mustache that creates a model property, and this is the how the API operation is created.

like image 162
Matt E. Avatar answered Sep 18 '22 12:09

Matt E.