Search code examples
c#swaggerswashbuckleautorestnswag

NSwag: Generate C# Client from multiple Versions of an API


We are versioning our API and generating the Swagger specification using Swashbuckle in ASP.NET Core 1.1. We can generate two API docs based on those JSON specification files:

<!-- language: c# -->
services.AddSwaggerGen(setupAction =>
{
    setupAction.SwaggerDoc("0.1", new Info { Title = "Api", Version = "0.1", Description = "API v0.1" });
    setupAction.SwaggerDoc("0.2", new Info { Title = "Api", Version = "0.2", Description = "API v0.2" });

    // more configuration omitted
}

We are including all actions in both spec files, unless it is mapped to a specific version using the [MapToApiVersion] and ApiExplorerSettings(GroupName ="<version>")] attributes. Methods belonging to an older version only are also decorated with the [Obsolete] attribute:

<!-- language: c# -->
[MapToApiVersion("0.1")]
[ApiExplorerSettings(GroupName = "0.1")]
[Obsolete]

However, we want to have only one C# Client generated from the Union of both spec files, where all methods are included in the Client, 0.1 as well as 0.2, but all obsolete methods marked, in fact, as obsolete.

I have looked into both NSwag (which we are using for quite some time now) as well as AutoRest. AutoRest seems to support a merging scenario, but I could not get it to work because of schema validation errors (and I am more than unsure whether our specific scenario would be actually supported).

My last idea as of now to get this sorted is to somehow JSON-merge the specs into one and then feed it to NSwag.

Do we miss anything here? Is this somehow possible to realize with NSwag?


Solution

  • I wrote an article about similar problem https://medium.com/dev-genius/nswag-charp-client-from-multiple-api-versions-7c79a3de4622

    First of all, create a schema. As I see, there are two approaches:

    • one schema where multiple versions are living
    • own schema for each version

    Next, create clients for each supported version and wrap them under the wrapper client:

    public class AppApiClient
    {
        public IV1Client V1 { get; }
        public IV2Client V2 { get; }
    
        public AppApiClient(HttpClient httpClient)
        {
            V1 = new V1Client(httpClient);
            V2 = new V2Client(httpClient);
        }
    }