Skip to content

Comparison with NSwag

fonlow edited this page Apr 2, 2022 · 12 revisions

The comparison is loosely related to "WebApiClientGen vs Swashbuckle.AspNetCore plus NSwag". The code generated by OpenApiClientGen is similar to what generated by WebApiClientGen. And for detailed comparison, please check Compare with NSwag of NSwagStudio v13.15.10.0.

Data Mapping

Primitive Types

From Open API to C#

{"integer int32", typeof(int) },
{"integer int64", typeof(long) },
{"integer", typeof(int) },
{"number float", typeof(float) },
{"number double", typeof(double) },
{"number", typeof(float) },
{"string", typeof(string) },
{"boolean", typeof(bool) },
{"string date", typeof(DateOnly) },
{"string date-time", typeof(DateTimeOffset) },

For DateOnly, please read more at "DateOnly in .NET 6 and ASP.NET Core 6".

From Open API to TypeScript

{"integer int32", "number" },
{"integer int64", "number" },
{"integer", "number" },
{"number float", "number" },
{"number double", "number" },
{"number", "number" },
{"string", "string" },
{"boolean", "boolean" },
{"string date", "Date" },
{"string date-time", "Date" },

NSwag uses fairly similar mappings.

Array

OpenApiClientGen

For example, Pet[] in C#, and Array<Pet> in TypeScript.

NSwag

For example, System.Collections.Generic.ICollection<Pet> in C#, and Pet[] in TypeScript.

Enum

OpenApiClientGen

C#

public enum PetStatus
{
        
    available = 0,
        
    pending = 1,
        
    sold = 2,
}

With setting EnumToString, the generated codes:

[System.Runtime.Serialization.DataContract(Namespace="http://pet.domain/2020/03")]
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public enum PetStatus
{
    
    [System.Runtime.Serialization.EnumMemberAttribute(Value="available")]
    available = 0,
    
    [System.Runtime.Serialization.EnumMemberAttribute(Value="pending")]
    pending = 1,
    
    [System.Runtime.Serialization.EnumMemberAttribute(Value="sold")]
    sold = 2,
}

TypeScript

export enum PetStatus { available = 0, pending = 1, sold = 2 }

With setting EnumToString, the generated codes:

 export enum PetStatus { available = 'available', pending = 'pending', sold = 'sold' }

NSwag

C#

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.7.0 (Newtonsoft.Json v12.0.0.0)")]
public enum Anonymous
{
    [System.Runtime.Serialization.EnumMember(Value = @"available")]
    Available = 0,
    
    [System.Runtime.Serialization.EnumMember(Value = @"pending")]
    Pending = 1,
    
    [System.Runtime.Serialization.EnumMember(Value = @"sold")]
    Sold = 2,
    
}
    
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.7.0 (Newtonsoft.Json v12.0.0.0)")]
public enum CatHuntingSkill
{
    [System.Runtime.Serialization.EnumMember(Value = @"clueless")]
    Clueless = 0,
    
    [System.Runtime.Serialization.EnumMember(Value = @"lazy")]
    Lazy = 1,
    
    [System.Runtime.Serialization.EnumMember(Value = @"adventurous")]
    Adventurous = 2,
    
    [System.Runtime.Serialization.EnumMember(Value = @"aggressive")]
    Aggressive = 3,
    
}

TypeScript

export enum Status {
    Available = "available",
    Pending = "pending",
    Sold = "sold",
}

export enum CatHuntingSkill {
    Clueless = "clueless",
    Lazy = "lazy",
    Adventurous = "adventurous",
    Aggressive = "aggressive",
}

What OpenApiClientGen does not support?

HTTP Headers

Open API specifications define the manipulations of HTTP headers. NSwag and many other tools support such definitions, and headers may appear in the parameters of generated client function prototypes. However OpenApiClientGen does not support respective definitions, by design. HTTP headers are generally for security and load balance, and it may be better to handle HTTP headers through HTTP interception, and most programming frameworks/libraries support HTTP interception.

When using client codes generated by OpenApiClientGen, you may use HTTP interception for the auth headers and HeadersCallback for manipulating other request headers in client codes.

XML Response

OpenApiClientGen supports only response in JSON and text. If response's content type is text/xml, respective operations will be skipped.

Remarks

NSwag does not seem to support XML response even though codes are still generated for XML responses.

Multiple Definitions of Error Responses

NSwag will typically yield the following:

                        var status_ = ((int)response_.StatusCode).ToString();
                        if (status_ == "200") 
                        {
                            return;
                        }
                        else
                        if (status_ == "480") 
                        {
                            var objectResponse_ = await ReadObjectResponseAsync<FileResponse>(response_, headers_).ConfigureAwait(false);
                            throw new ApiException("ScalingActivityInProgressFault", (int)response_.StatusCode, objectResponse_.Text, headers_, objectResponse_.Object);
                        }
                        else
                        if (status_ == "481") 
                        {
                            var objectResponse_ = await ReadObjectResponseAsync<FileResponse>(response_, headers_).ConfigureAwait(false);
                            throw new ApiException("ResourceContentionFault", (int)response_.StatusCode, objectResponse_.Text, headers_, objectResponse_.Object);
                        }
                        else
                        if (status_ == "482") 
                        {
                            var objectResponse_ = await ReadObjectResponseAsync<FileResponse>(response_, headers_).ConfigureAwait(false);
                            throw new ApiException("ServiceLinkedRoleFailure", (int)response_.StatusCode, objectResponse_.Text, headers_, objectResponse_.Object);
                        }
                        else
                        if (status_ != "200" && status_ != "204")
                        {
                            var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); 
                            throw new ApiException("The HTTP status code of the response was not expected (" + (int)response_.StatusCode + ").", (int)response_.StatusCode, responseData_, headers_, null);
                        }

OpenApiClientGen just throws HttpRequestException or WebApiRequestException, and it is up to the client codes to do respective type casts.

Misc.

For generating custom complex data types in TypeScript, NSwag offers an option of generating classes, while OpenApiClientGen generates only interfaces. This is because, mapping data from a service to clients, all you need is a contract, and interface is all you need for defining the contract.

NSwag yields verbose GeneratedCodeAttribute. The GeneratedCodeAttribute class can be used by code analysis tools to identify computer-generated code, and to provide an analysis based on the tool and the version of the tool that generated the code. However it is a good practice to put generated codes into a dedicated assembly with generated codes only. Thus an application programmer may simply exclude the assembly from code analysis tools. Therefore, GeneratedCodeAttribute may be unnecessary in the generated codes.

Detailed Comparison with Examples