{
  "$type": "site.standard.document",
  "canonicalUrl": "https://johnnyreilly.com/posts/nswag-generated-c-sharp-client-property-name-clash",
  "description": "Generate C# and TypeScript client libraries from OpenAPI / Swagger definitions using NSwag while overcoming language conflicts and numeric types.",
  "path": "/posts/nswag-generated-c-sharp-client-property-name-clash",
  "publishedAt": "2021-10-31T00:00:00.000Z",
  "site": "at://did:plc:yy3apqjlms24kso7ahn7lbmb/site.standard.publication/3mova7c4nho2b",
  "tags": [
    "c#",
    "swagger"
  ],
  "textContent": "NSwag is a great tool for generating client libraries in Cand TypeScript from Open API / Swagger definitions. You can face issues where Open API property names collide due to the nature of the Clanguage, and when you want to use decimal for your floating point numeric type over double. This post demonstrates how to get over both issues.\n\n\n\nMake a CClient Generator\n\nLet's get a console app set up that will allow us to generate a Cclient using an Open API file:\n\nWe'll also add a petstore-simple.json file to our project which we'll borrow from https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v2.0/json/petstore-simple.json (home of the Open API specification):\n\nWe'll tweak our NSwag.csproj file to ensure that the json file is included in our build output:\n\nThis will give us a console app with a reference to NSwag. Now we'll flesh out the Program.cs file thusly:\n\nIf we perform a dotnet run we now pump out a GeneratedClient.cs file which is a Cclient library for the pet store. Fabulous.\n\nSo far so dandy. We're taking an Open API json file and generating a Cclient library from it.\n\nWhen properties collide\n\nIt's time to break things. We're presently generating a Pet class that looks like this:\n\nWe're going to take our Pet definition in the petstore-simple.json file, and add a new @id property alongside the id property:\n\nFor why? Whilst this may seem esoteric, this is a scenario that can present. It's not unknown to encounter properties which are identical, save for an @ prefix. This is often the case for meta-properties.\n\nWhat do we get if we run our generator over that?\n\nWe get code that doesn't compile. You can't have two properties in a Cclass with the same name. You also cannot have @ as a character in a Cproperty or variable name. To quote the docs:\n\n> The @ special character serves as a verbatim identifier.\n\nIt so happens that, by default, NSwag purges @ characters from property names. If there isn't another property which is named the same save for an @ prefix, this is a fine strategy. If there is, as for us now, you're toast.\n\nThere's a workaround. We'll create a new HandleAtCSharpPropertyNameGenerator class:\n\nThis is a replacement for the CSharpPropertyNameGenerator that NSwag ships with. Rather than purging the @ character, it replaces usage with a double underscore: __.\n\nWe'll make use of our new PropertyNameGenerator:\n\nWith this in place, when we dotnet run we create a class that looks like this:\n\nSo the newly generated property name is __id rather than the clashing Id. Rather wonderfully, this works. It resolves the issue we faced. We've chosen to use __ as our prefix - we could choose something else if that worked better for us.\n\nKnowing that this hook exists is super useful.\n\nUse decimal not double for floating point numbers\n\nAnother common problem with generated Cclients is the number type used to represent floating point numbers. The default for Cis double.\n\nThis is a reasonable choice when you consider the official format for highly precise floating point numbers is double:\n\n> OpenAPI has two numeric types, number and integer, where number includes both integer and floating-point numbers. An optional format keyword serves as a hint for the tools to use a specific numeric type:\n>\n> float - Floating-point numbers.\n> double - Floating-point numbers with double precision.\n\nLet's tweak our pet definition to reflect this:\n\nWith this in place, when we dotnet run we create a class that looks like this:\n\nCdevelopers may well rather work with a decimal type which can handle \"financial calculations that require large numbers of significant integral and fractional digits and no round-off errors\".\n\nThere is a way to switch from using double to decimal in your generated clients. I've been using the approach for some years, and I suspect I first adapted it from a comment on GitHub.\n\nIt uses the visitor pattern and looks like this:\n\nThe code above, when invoked upon our OpenApiDocument, changes the format of all number types to be decimal. Which results in code along these lines:\n\nIf we take all the code, and put it together, we end up with this:\n\nConclusion\n\nThis post takes the tremendous NSwag, and demonstrates a mechanism for using it to create Cclients from an Open API / Swagger documents which:\n\n- can handle property names with an @ prefix which might collide with the same property without the prefix\n- use decimal as the preferred number type for floating point numbers",
  "title": "NSwag generated C# client: Open API property name clashes and decimal types rather than double"
}