/ CODING, ASPNETCORE

Automatically generating API clients on build with NSwag

TL;DR

Want to know how you can generate and compile up to date API clients each time you build your solution? Take a look at this example on GitHub.

Background

When you create an API using aspnetcore it is very easy to add a Swagger endpoint and SwaggerUI for exploring and testing your API. Once you have Swagger enabled you can also use the information Swagger exposes about your API to generate clients for the enpoints and operations your aspnet controllers expose.

With NSwag you can generate client code without having your API running, many generators require the swagger.json file that is exposed when you run your API but NSwag doesn’t.

In this blogpost I will show you how to configure Swagger an NSwag so that up to date API clients are generated and compiled each time you build your solution. These clients can be packaged and published through NuGet for easy access to your API’s.

Configure Swagger and SwaggerUI with NSwag

First add the NSwag.AspNetCore NuGet package to your API project:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <AssemblyName>Example.Api</AssemblyName>
    <RootNamespace>Example.Api</RootNamespace>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

  <ItemGroup>
    <Folder Include="wwwroot\" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="NSwag.AspNetCore" Version="12.0.13" />
  </ItemGroup>

</Project>

Next add the following code to your Startup.cs:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
  // .....
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddSwaggerDocument(settings =>
    {
        settings.PostProcess = document =>
        {
            document.Info.Version = "v1";
            document.Info.Title = "Example API";
            document.Info.Description = "REST API for example.";
        };
    });
    //.....
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // .....
    // Enable the Swagger UI middleware and the Swagger generator
    app.UseSwagger();
    app.UseSwaggerUi3();
    // .....
}

This is enough for a basic Swagger configuration, if you run your aspnetcore API project and navigate to http://<host>:<port>/swagger you will see SwaggerUI. This will also expose a swagger.json document at http://<host>:<port>/swagger/v1/swagger.json describing your API.

For more eloborate examples or explanation on how to configure NSwag have a look at the documentation for configuring the aspnetcore middleware.

Generate API clients with NSwag

Next setup a seperate Clients project (or whatever you want to name it) and add the NSwag.MSBuild NuGet packages to it. We will use this package to generate the code for our API clients before the project is build, this way we can generate our code and compile it everytime you build your project.

There are 3 things you need to add to your project file to config this:

  • an MSBuild property called GenerateCode inside a PropertyGroup with the value True
  • a PackageReference to NSwag.MSBuild insid a ItemGroup
  • a custom Target that runs before the PrepareForBuild target with a Condition. This target will invoke nswag.exe using an nswag.json config file to generate the required code.

Your project file has to look something like this:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <AssemblyName>Example.Api.Client</AssemblyName>
    <RootNamespace>Example.Api.Client</RootNamespace>
    <GenerateCode>True</GenerateCode>
  </PropertyGroup>
<ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
    <PackageReference Include="NSwag.MSBuild" Version="12.0.13">
      <PrivateAssets>All</PrivateAssets>
    </PackageReference>
  </ItemGroup>
  
  <Target Name="NSwag" BeforeTargets="PrepareForBuild" Condition="'$(GenerateCode)'=='True' ">
    <Exec Command="$(NSwagExe_Core22) run nswag.json /variables:Configuration=$(Configuration)" />
  </Target>
</Project>

You can pass /p:GenerateCode=False to dotnet.exe when building to disable the code generation. I use this on the CI server so that the version of the code that is in source controll will be used instead of being regenerated.

The easiest way to create a nswag.json config file is by using NSwagStudio which you can install on Windows using an MSI you can find here or you can take the nswag.json file from my example repository on github and make modifications in that.

Below are the most important properties for this example (get the full nswag.json file here):

{
    "runtime": "NetCore22",
    "defaultVariables": null,
    "swaggerGenerator": {
        "aspNetCoreToSwagger": {
            "project": "../Api/Api.csproj", //path to your aspnetcore 2.1 project
            //...
        }
    },
    "codeGenerators": {
        "swaggerToCSharpClient": {
            "clientBaseClass": "ClientBase", //name of your client base class
            "configurationClass": null,
            "generateClientClasses": true,
            "generateClientInterfaces": true,
            ...
            "useHttpRequestMessageCreationMethod": true, //allows you to add headers to each message
            "clientClassAccessModifier": "internal", //make client generated client implementations internal
            "typeAccessModifier": "public", //make your models and client interfaces public
            "generateContractsOutput": true, //generate contacts in a separte file
            "contractsNamespace": "Example.Api.Client.Contracts", //contracts namespace
            "contractsOutputFilePath": "Contracts.g.cs",
            ...
            "namespace": "Example.Api.Client", //clients namespace
            ...
            "output": "Client.g.cs"
        }
    }
}

The most important part is the useHttpRequestMessageCreationMethod and clientBaseClass, this allows you to define a base class in your Client project that will create the HttpMessage that your clients will send. This allows you to for example add an Authorization header with a Bearer token. The client base class below does just that:

internal abstract class ClientBase
  {
      public Func<Task<string>> RetrieveAuthorizationToken { get; set; }

      // Called by implementing swagger client classes
      protected async Task<HttpRequestMessage> CreateHttpRequestMessageAsync(CancellationToken cancellationToken)
      {
          var msg = new HttpRequestMessage();

          if (RetrieveAuthorizationToken != null)
          {
              var token = await RetrieveAuthorizationToken();
              msg.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
          }
          return msg;
      }

  }

I chose for a Func<..> in my base class to retrieve the Bearer token. This Func<..> is invoked each time a message is created, this way the code that uses your client can contain logic to retrieve a new token when the current one is expired.

Also I made my client implementations internal and expose a public interfaces. For this to work you will have to add a public factory or some other public mechanism to create instances of your clients. Here is an example of my factory:

public static class ClientFactory
  {
      public static IValuesClient CreateValuesClient(string baseUrl, HttpClient http, Func<Task<string>> retrieveAuthorizationToken)
      {
          return new ValuesClient(baseUrl, http)
          {
              RetrieveAuthorizationToken = retrieveAuthorizationToken
          };
      }
  }

Now build the Client project to generate the clients and contracts. All that is left to do is to package your Client project as a NuGet package and share it with the users of your API. Having the Client project in the same solution as your aspnetcore API allows you to automatically build and publish up to date clients for your API.

A fully working example is available on GitHub. If you encounter issues with this example create an issue on that repository or leave a comment here.

NSwag has a bunch of options to customize and tweak how the clients and contracts are generated. I have only shown you a very basic example. For example NSwag can also generate Typescript clients. Take a look at the wiki for NSwag if you want to know how to do this and what else NSwag can do.

Credits

Cover photo by unsplash-logoModestas Urbonas

Updates

  • 02/13/2019: updated examples to aspnetcore 2.2 and NSwag 12.