Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Typescript

WebApiClientGen vs Swashbuckle plus NSwag

4.00/5 (8 votes)
8 May 2020CPOL7 min read 34.2K  
Compare what is supported in WebApiClientGen and NSwagStudio

Introduction

This article compares Strongly Typed Client API Generators with Swagger toolchains in the .NET landscapes, so you could choose the right tools for the right contexts. It is presumed that you have experience in Swagger toolchains and you have read at least one of the following articles:

While Swagger toolchains are mostly and primarily for meta first approach, there are tools supporting code first approaches, that is, the server side tools generate Swagger definition files and the client tools generate codes based on the definitions, while WebApiClientGen generates client codes directly on the server side during the service development. And this article is focused on the code first approach, specifically with Swashbuckle.AspNetCore plus NSwagStudio, since these two are promoted in Microsoft Docs.

C# Clients

As its name had suggested, Strongly Typed Client API Generators provide exact data type mappings between server and C# clients, as precise as possible.

Swashbuckle+NSwag Does Not Support

  1. User defined struct
  2. Object
  3. dynamic
  4. Generic
  5. Namespace
  6. Enum

Remarks

  • Swashbuckle translates server side struct System.Drawing.Point to client side class Point.
  • Open API and NSwag supports inheritance, however Swashbuckle's support for inheritance is poor, as of Swashbuckle.AspNetCore 5.0.
  • Open API and NSwag provide limited supports for enum, however, Swashbuckle supports even less.
  • NSwag does support namespace and enum, however, not worrking well with the Swagger definition file generated by Swashbuckle.AspNet Core 5.0.

Swashbuckle+NSwag Provides Imprecise Data Type Mappings for the Following Types

  1. Decimal ==> double
  2. Nullable<T> ==> T
  3. float ==>double
  4. uint, short, byte ==> int
  5. ulong ==> long
  6. char==> string
  7. Tuple ==> Generated user defined type with similar structure to Tuple
  8. int[,] ==> ICollection<object>
  9. int[][] ==> ICollection<int>
  10. KeyValuePair ==> Generated user defined type with similar structure to KeyValuePair

NSwag Generates Verbose, Larger and Complex Codes

In the sln of SwaggerDemo, Core3WebApi is with WebApiClientGen, and SwaggerDemo is with Swashbuckle.AspNetCore for creating an Open API definition. When generating async functions only, codes generated by WebApiClientGen is 97KB, along with debug build 166KB and release build 117KB, while Swagger's NSwagStudio gives 489KB-495KB, along with debug build 340KB-343KB and release build 263KB-283KB. There might be good reasons why NSwag generates complex codes, and you may inspect and compare to see whether such complexity is needed in your project content and contexts.

NSwag Yields Verbose GeneratedCodeAttribute

According to this, 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.

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 is not necessary in the generated codes.

TypeScript Clients for JavaScript Libraries or Frameworks

WebApiClientGen

  • jQuery with callbacks
  • Angular 2+
  • Axios
  • Aurelia
  • Fetch API

NSwag

  • JQuery with Callbacks
  • JQuery with promises
  • Angular (v2+) using the http service
  • window.fetch API and ES6 promises
  • Aurelia using the HttpClient from aurelia-fetch-client
  • Axios (preview)

How is WebApiClientGen Superior to Swagger?

For generating C# clients, WebApiClientGen supports more .NET built-in data types and gives more exact data type mappings. Exact type mappings make client programming much easier for high quality since the integration tests should pick up data out of range easily because of proper type constraints.

Smaller codes and smaller compiled images are always welcome.

The manual steps of generating client codes is less and faster.

Remarks

Swashbuckle.AspNetCore does not support types with the same name but in different namespaces. In complex business applications, there may be custom data types with the same names in different namespaces.

How is Swagger Superior to WebApiClientGen?

Swagger here means the Open API standard and respective toolchains.

Swagger is an open standard and platform neutral, being supported by major software vendors and developed by hundreds of developers around the world. Microsoft Docs has a dedicated section for Swagger here, and Microsoft has been using Swagger for her own Web API products.

Swagger supports fine grained control over HTTP headers, while WebApiClientGen ignores this area.

How About Online Help?

Swashbuckle.AspNetCore provides "a rich, customizable experience for describing the web API functionality".

WebApiClientGen copies in-source documents of published data types and controller operations to client codes, and decent IDE like Visual Studio could display intellisense along with the in-source documents in the client codes. This minimizes the need for online help.

If you really want online help, you may use Sandcastle for C# client codes, use Compodoc for Angular 2+ client codes, and use TypeDoc for other JavaScript frameworks.

Differences on Preferences

Swagger/Open API is designed for RESTful service, while ASP.NET Web API is designed for RPC which covers RESTful service. And the design preferences of WebApiClientGen is based on RPC, not REST. From a certain point of view, REST is a disciplined or constrained way of building RPC. For building complex business applications, REST may be beneficial to overall development, or may be too technical and forcing developers to translate high level business logic into REST, rather than to work on business domain modeling.

“Consider how often we see software projects begin with adoption of the latest fad in architectural design, and only later discover whether or not the system requirements call for such an architecture.”

References

Can WebApiClientGen and Swagger Coexist?

The answer is yes.

The Swagger toolchains and WebApiClientGen are greatly overlapping in the .NET landscapes, while Swagger covers wider and deeper spectrum, and WebApiClientGen is optimized for SDLC with .NET Framework and .NET Core, as well as strongly typing.

If you are developing ASP.NET (Core) Web API and expect all clients are coded in C# and TypeScript only, WebApiClientGen gives you more advantages.

When you need to support clients coded in languages other than C# and TypeScript, you may introduce Swashbuckle into your Web API and generate the Open API definition files either in JSON or YAML, then use NSwag or other Swagger/Open API tools for clients.

Perfect SDLC with WebApiClientGen and Swagger

Whenever you as a backend developer have just updated the Web API, you run WebApiClientGen with a batch file to generate C# client codes and TypeScript client codes for client application developers. And the Swagger endpoint of the Web API gives the Open API definition files, so client application developers working on other languages may generate client API codes in other languages.

So you get the best of WebApiClientGen and Swagger/Open API.

Points of Interest

When writing this article, I had done a detailed study on Swagger/Open API Specification since I had done a similar study in 2015 when the WebApiClientGen project was started. The landscape of generating codes from Swagger had been changed a lot with comprehensive and matured toolchains for a wide variety of server platforms and client platforms. However, existing client codegen tools for C# and TypeScript could not satisfy me, if I have a 3rd party service to consume, which does not provide client libraries but some definition files of Swagger/Open API Specification. It shouldn't be hard to write an alternative to NSwag or Autorest, based on core components of WebApiClientGen. Here you are: OpenApiClientGen. And the Wiki of this project has pages to compare what generated by NSwag and OpenApiClientGen based on the same set of Swagger/Open API definitions.

Appendixes

The appendixes give you some basic comparisons of codes generated by Swagger and WebApiClientGen, when you are considering your SDLC and the contexts of your SDLC.

Type Person in Services

C#
/// <summary>
/// Base class of company and person
/// </summary>
[DataContract(Namespace = Constants.DataNamespace)]
public class Entity
{
    public Entity()
    {
        Addresses = new List<Address>();
    }

    [DataMember]
    public Guid Id { get; set; }

    /// <summary>
    /// Name of the entity.
    /// </summary>
    [DataMember(IsRequired =true)]//MVC and Web API does not care
    [System.ComponentModel.DataAnnotations.Required]//MVC and Web API care about only this
    public string Name { get; set; }

    /// <summary>
    /// Multiple addresses
    /// </summary>
    [DataMember]
    public IList<Address> Addresses { get; set; }

    [DataMember]
    public virtual ObservableCollection<PhoneNumber> PhoneNumbers { get; set; }

    public override string ToString()
    {
        return Name;
    }

    [DataMember]
    public Uri Web { get; set; }
}

[DataContract(Namespace = Constants.DataNamespace)]
public class Person : Entity
{
    [DataMember]
    public string Surname { get; set; }
    [DataMember]
    public string GivenName { get; set; }

    /// <summary>
    /// Date of Birth.
    /// This is optional.
    /// </summary>
    [DataMember]
    public DateTime? DOB { get; set; }

    public override string ToString()
    {
        return Surname + ", " + GivenName;
    }
}

C# Client Codes Generated by NSwagStudio

C#
[System.CodeDom.Compiler.GeneratedCode
("NJsonSchema", "10.1.4.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class Entity
{
    [Newtonsoft.Json.JsonProperty("id",
    Required = Newtonsoft.Json.Required.DisallowNull,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Guid Id { get; set; }

    [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)]
    [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
    public string Name { get; set; }

    [Newtonsoft.Json.JsonProperty("addresses",
    Required = Newtonsoft.Json.Required.Default,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Collections.Generic.ICollection<Address> Addresses { get; set; }

    [Newtonsoft.Json.JsonProperty("phoneNumbers",
    Required = Newtonsoft.Json.Required.Default,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Collections.Generic.ICollection<PhoneNumber> PhoneNumbers { get; set; }

    [Newtonsoft.Json.JsonProperty("web",
    Required = Newtonsoft.Json.Required.Default,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Uri Web { get; set; }
}

[System.CodeDom.Compiler.GeneratedCode
("NJsonSchema", "10.1.4.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class Person
{
    [Newtonsoft.Json.JsonProperty("surname",
    Required = Newtonsoft.Json.Required.Default,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public string Surname { get; set; }

    [Newtonsoft.Json.JsonProperty("givenName",
    Required = Newtonsoft.Json.Required.Default,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public string GivenName { get; set; }

    [Newtonsoft.Json.JsonProperty("dob",
    Required = Newtonsoft.Json.Required.Default,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.DateTimeOffset? Dob { get; set; }

    [Newtonsoft.Json.JsonProperty("id",
    Required = Newtonsoft.Json.Required.DisallowNull,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Guid Id { get; set; }

    [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)]
    [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
    public string Name { get; set; }

    [Newtonsoft.Json.JsonProperty("addresses",
    Required = Newtonsoft.Json.Required.Default,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Collections.Generic.ICollection<Address> Addresses { get; set; }

    [Newtonsoft.Json.JsonProperty("phoneNumbers",
    Required = Newtonsoft.Json.Required.Default,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Collections.Generic.ICollection<PhoneNumber> PhoneNumbers { get; set; }

    [Newtonsoft.Json.JsonProperty("web",
    Required = Newtonsoft.Json.Required.Default,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Uri Web { get; set; }
}

C# Client Codes Generated by WebApiClientGen

C#
/// <summary>
/// Base class of company and person
/// </summary>
public class Entity : object
{
    /// <summary>
    /// Multiple addresses
    /// </summary>
    public DemoWebApi.DemoData.Client.Address[] Addresses { get; set; }

    public System.Guid Id { get; set; }

    /// <summary>
    /// Name of the entity.
    /// </summary>
    [System.ComponentModel.DataAnnotations.RequiredAttribute()]
    public string Name { get; set; }

    public DemoWebApi.DemoData.Client.PhoneNumber[] PhoneNumbers { get; set; }
}

public class Person : DemoWebApi.DemoData.Client.Entity
{
    /// <summary>
    /// Date of Birth.
    /// This is optional.
    /// </summary>
    public System.Nullable<System.DateTime> DOB { get; set; }

    public string GivenName { get; set; }

    public string Surname { get; set; }
}

TypeScript Client Codes Generated by NSwagStudio

JavaScript
export interface IEntity {
    id?: string;
    name: string;
    addresses?: Address[] | undefined;
    phoneNumbers?: PhoneNumber[] | undefined;
    web?: string | undefined;
}

interface IPerson {
    surname?: string | undefined;
    givenName?: string | undefined;
    dob?: Date | undefined;
    id?: string;
    name: string;
    addresses?: Address[] | undefined;
    phoneNumbers?: PhoneNumber[] | undefined;
    web?: string | undefined;
}

TypeScript Client Codes Generated by WebApiClientGen

JavaScript
/**
 * Base class of company and person
 */
export interface Entity {

    /**
     * Multiple addresses
     */
    addresses?: Array<DemoWebApi_DemoData_Client.Address>;
    id?: string;

    /**
     * Name of the entity.
     */
    name: string;
    phoneNumbers?: Array<DemoWebApi_DemoData_Client.PhoneNumber>;
    web?: string;
}

export interface Person extends DemoWebApi_DemoData_Client.Entity {

    /**
     * Date of Birth.
     * This is optional.
     */
    dob?: Date;
    givenName?: string;
    surname?: string;
}

Type enum PhoneType and Days

C#
/// <summary>
/// Phone type
/// Tel, Mobile, Skyp and Fax
///
/// </summary>
[DataContract(Namespace = Constants.DataNamespace)]
public enum PhoneType
{
    /// <summary>
    /// Land line
    /// </summary>
    [EnumMember]
    Tel = 0,

    /// <summary>
    /// Mobile phone
    /// </summary>
    [EnumMember]
    Mobile = 1,

    [EnumMember]
    Skype = 2,
    [EnumMember]
    Fax = 3,
}

[DataContract(Namespace = Constants.DataNamespace)]
public enum Days
{
    [EnumMember]
    Sat = 1,
    [EnumMember]
    Sun,
    [EnumMember]
    Mon,
    [EnumMember]
    Tue,
    [EnumMember]
    Wed,
    /// <summary>
    /// Thursday
    /// </summary>
    [EnumMember]
    Thu,
    [EnumMember]
    Fri
};

C# Client Codes Generated by NSwagStudio

C#
[System.CodeDom.Compiler.GeneratedCode
("NJsonSchema", "10.1.4.0 (Newtonsoft.Json v12.0.0.0)")]
public enum PhoneType
{
    _0 = 0,

    _1 = 1,

    _2 = 2,

    _3 = 3,
}

[System.CodeDom.Compiler.GeneratedCode
("NJsonSchema", "10.1.4.0 (Newtonsoft.Json v12.0.0.0)")]
public enum Days
{
    _1 = 1,

    _2 = 2,

    _3 = 3,

    _4 = 4,

    _5 = 5,

    _6 = 6,

    _7 = 7,
}

C# Client Code Generated by WebApiClientGen

C#
/// <summary>
/// Phone type
/// Tel, Mobile, Skyp and Fax
///
/// </summary>
public enum PhoneType
{
    /// <summary>
    /// Land line
    /// </summary>
    Tel,

    /// <summary>
    /// Mobile phone
    /// </summary>
    Mobile,

    Skype,

    Fax,
}

public enum Days
{
    Sat = 1,

    Sun = 2,

    Mon = 3,

    Tue = 4,

    Wed = 5,

    /// <summary>
    /// Thursday
    /// </summary>
    Thu = 6,

    Fri = 7,
}

TypeScript Client Codes Generated by NSwagStudio

JavaScript
enum PhoneType {
    _0 = 0,
    _1 = 1,
    _2 = 2,
    _3 = 3,
}
enum Days {
    _1 = 1,
    _2 = 2,
    _3 = 3,
    _4 = 4,
    _5 = 5,
    _6 = 6,
    _7 = 7,
}

TypeScript Client Generated by WebApiClientGen

JavaScript
/**
 * Phone type
 * Tel, Mobile, Skyp and Fax
 */
export enum PhoneType {

    /**
     * Land line
     */
    Tel,

    /**
     * Mobile phone
     */
    Mobile,
    Skype,
    Fax
}

export enum Days {
    Sat = 1,
    Sun = 2,
    Mon = 3,
    Tue = 4,
    Wed = 5,

    /**
     * Thursday
     */
    Thu = 6,
    Fri = 7
}

Controller Operation HeroesController.Get(id)

C#
/// <summary>
/// Get a hero.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("{id}")]
public Hero Get(long id)
{...

C# Client Codes Generated by NSwagStudio

C#
       /// <returns>Success</returns>
        /// <exception cref="ApiException">A server side error occurred.</exception>
        public System.Threading.Tasks.Task<Hero> HeroesGetAsync(long id)
        {
            return HeroesGetAsync(id, System.Threading.CancellationToken.None);
        }
    
        /// <param name="cancellationToken">A cancellation token that 
        /// can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>Success</returns>
        /// <exception cref="ApiException">A server side error occurred.</exception>
        public async System.Threading.Tasks.Task<Hero> 
        HeroesGetAsync(long id, System.Threading.CancellationToken cancellationToken)
        {
            if (id == null)
                throw new System.ArgumentNullException("id");
    
            var urlBuilder_ = new System.Text.StringBuilder();
            urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : 
            "").Append("/api/Heroes/{id}");
            urlBuilder_.Replace("{id}", System.Uri.EscapeDataString
            (ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture)));
    
            var client_ = _httpClient;
            try
            {
                using (var request_ = new System.Net.Http.HttpRequestMessage())
                {
                    request_.Method = new System.Net.Http.HttpMethod("GET");
                    request_.Headers.Accept.Add
                    (System.Net.Http.Headers.
                        MediaTypeWithQualityHeaderValue.Parse("text/plain"));
    
                    PrepareRequest(client_, request_, urlBuilder_);
                    var url_ = urlBuilder_.ToString();
                    request_.RequestUri = 
                         new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
                    PrepareRequest(client_, request_, url_);
    
                    var response_ = await client_.SendAsync(request_, 
                    System.Net.Http.HttpCompletionOption.ResponseHeadersRead, 
                                 cancellationToken).ConfigureAwait(false);
                    try
                    {
                        var headers_ = System.Linq.Enumerable.ToDictionary
                        (response_.Headers, h_ => h_.Key, h_ => h_.Value);
                        if (response_.Content != null && response_.Content.Headers != null)
                        {
                            foreach (var item_ in response_.Content.Headers)
                                headers_[item_.Key] = item_.Value;
                        }
    
                        ProcessResponse(client_, response_);
    
                        var status_ = ((int)response_.StatusCode).ToString();
                        if (status_ == "200") 
                        {
                            var objectResponse_ = 
                            await ReadObjectResponseAsync<Hero>(response_, headers_).
                                                         ConfigureAwait(false);
                            return 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);
                        }
            
                        return default(Hero);
                    }
                    finally
                    {
                        if (response_ != null)
                            response_.Dispose();
                    }
                }
            }
            finally
            {
            }
        }

C# Client Codes Generated by WebApiClientGen

C#
        /// <summary>
        /// Get a hero.
        /// GET api/Heroes/{id}
        /// </summary>
        public async Task<DemoWebApi.Controllers.Client.Hero> GetHeroAsync(long id)
        {
            var requestUri = new Uri(this.baseUri, "api/Heroes/"+id);
            var responseMessage = await client.GetAsync(requestUri);
            try
            {
                responseMessage.EnsureSuccessStatusCode();
                var stream = await responseMessage.Content.ReadAsStreamAsync();
                using (JsonReader jsonReader = 
                       new JsonTextReader(new System.IO.StreamReader(stream)))
                {
                var serializer = new JsonSerializer();
                return serializer.Deserialize<DemoWebApi.Controllers.Client.Hero>(jsonReader);
                }
            }
            finally
            {
                responseMessage.Dispose();
            }
        } 

TypeScript Fetch API Codes Generated by NSwagStudio

JavaScript
/**
 * @return Success
 */
heroesGet(id: number): Promise<Hero> {
    let url_ = this.baseUrl + "/api/Heroes/{id}";
    if (id === undefined || id === null)
        throw new Error("The parameter 'id' must be defined.");
    url_ = url_.replace("{id}", encodeURIComponent("" + id));
    url_ = url_.replace(/[?&]$/, "");

    let options_ = <RequestInit>{
        method: "GET",
        headers: {
            "Accept": "text/plain"
        }
    };

    return this.http.fetch(url_, options_).then((_response: Response) => {
        return this.processHeroesGet(_response);
    });
}

protected processHeroesGet(response: Response): Promise<Hero> {
    const status = response.status;
    let _headers: any = {}; if (response.headers && response.headers.forEach)
    { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
    if (status === 200) {
        return response.text().then((_responseText) => {
        let result200: any = null;
        let resultData200 = _responseText === "" ?
        null : JSON.parse(_responseText, this.jsonParseReviver);
        result200 = Hero.fromJS(resultData200);
        return result200;
        });
    } else if (status !== 200 && status !== 204) {
        return response.text().then((_responseText) => {
        return throwException
        ("An unexpected server error occurred.", status, _responseText, _headers);
        });
    }
    return Promise.resolve<Hero>(<any>null);
}

TypeScript Fetch API Codes Generated by WebApiClientGen

JavaScript
/**
 * Get a hero.
 * GET api/Heroes/{id}
 */
getHero(id: number): Promise<DemoWebApi_Controllers_Client.Hero> {
    return fetch(this.baseUri + 'api/Heroes/' + id,
    {method: 'get'}).then(d => d.json());
}

TypeScript Angular API Codes Generated by NSwagStudio

JavaScript
    /**
     * @return Success
     */
    heroesGet(id: number): Observable<Hero> {
        let url_ = this.baseUrl + "/api/Heroes/{id}";
        if (id === undefined || id === null)
            throw new Error("The parameter 'id' must be defined.");
        url_ = url_.replace("{id}", encodeURIComponent("" + id)); 
        url_ = url_.replace(/[?&]$/, "");

        let options_ : any = {
            observe: "response",
            responseType: "blob",            
            headers: new HttpHeaders({
                "Accept": "text/plain"
            })
        };

        return this.http.request("get", url_, options_).pipe
        (_observableMergeMap((response_ : any) => {
            return this.processHeroesGet(response_);
        })).pipe(_observableCatch((response_: any) => {
            if (response_ instanceof HttpResponseBase) {
                try {
                    return this.processHeroesGet(<any>response_);
                } catch (e) {
                    return <Observable<Hero>><any>_observableThrow(e);
                }
            } else
                return <Observable<Hero>><any>_observableThrow(response_);
        }));
    }

    protected processHeroesGet(response: HttpResponseBase): Observable<Hero> {
        const status = response.status;
        const responseBlob = 
            response instanceof HttpResponse ? response.body : 
            (<any>response).error instanceof Blob ? (<any>response).error : undefined;

        let _headers: any = {}; 
        if (response.headers) { for (let key of response.headers.keys()) 
        { _headers[key] = response.headers.get(key); }};
        if (status === 200) {
            return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => {
            let result200: any = null;
            let resultData200 = _responseText === "" ? 
            null : JSON.parse(_responseText, this.jsonParseReviver);
            result200 = Hero.fromJS(resultData200);
            return _observableOf(result200);
            }));
        } else if (status !== 200 && status !== 204) {
            return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => {
            return throwException("An unexpected server error occurred.", 
            status, _responseText, _headers);
            }));
        }
        return _observableOf<Hero>(<any>null);
    }

TypeScript Angular API Codes Generated by WebApiClientGen

JavaScript
/**
 * Get a hero.
 * GET api/Heroes/{id}
 */
getById(id: number): Observable<DemoWebApi_Controllers_Client.Hero> {
    return this.http.get<DemoWebApi_Controllers_Client.Hero>
    (this.baseUri + 'api/Heroes/' + id);
}

History

  • 24th February, 2020: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)