Learn ASP.NET Core 3.1 with mini project : MVC, Razor Pages, Web API, Entity Framework Core, and Blazor. Hands-on online training course starting in July 2020. Click here to know more.

Create a TypeScript class to invoke ASP.NET Core Web API

In the previous part of this series you learned about TypeScript functions. Now it's time to peek into some more interesting features. To that end this part discuses three of them - interfaces and classes. You will build a fully functional class that helps you invoke an ASP.NET Core Web API. You then perform CRUD operations using the class developed in this exercise.

The following page shows the said class in action.

At the top there are five buttons. The click event handlers of these buttons invoke the respective action of  Employees Web API. For example, clicking the Get button invokes the Get() action of Web API and displays a list of employees in a table.

This example uses a TypeScript enum, TypeScript interfaces, and TypeScript classes to accomplish the task. So, let's get going.

Begin by adding a new TypeScript file named Classes.ts in the TypeScript folder.

Then add the HttpVerbs enumeration in the file as shown below:

enum HttpVerbs {
  GET = "GET",
  POST = "POST",
  PUT = "PUT",
  DELETE = "DELETE"
}

The HttpVerbs string enumeration holds items that represent HTTP verbs such as GET, POST, PUT, and DELETE. These values are used while invoking a Web API.

We could have jump straight into creating the classes but we would rather prefer to create a few interfaces first and then the classes will implement the interfaces. This will also help you learn how to create interfaces in TypeScript.

Take a look at the following interface called IEmployee.

interface IEmployee {
    employeeID?: number;
    firstName: string;
    lastName: string;
    title: string;
}

The IEmployee interface has four members namely employeID, firstName, lastName, and title. An object that implements IEmployee interface is requires to have its members. In this case employeeID is suffixed with ? indicating that it's an optional member. But the other members are mandatory. So, an object implementing IEmployee must contain firstName, lastName, and title properties and optionally it can also contain employeeID property.

Just to make this clear here is an example:

let emp : IEmployee;
emp = {
  employeeID:1,
  firstName:"Nancy",
  lastName:"Davolio",
  title : "Sales Executive"
}

And this is also alright:

let emp : IEmployee;
emp = {
  firstName:"Nancy",
  lastName:"Davolio",
  title : "Sales Executive"
}

Interfaces are not limited to property definitions. They can also contain function declarations. An object implementing that interface is then required to have those functions.

Let's define an interface called IEmployeeApiClient that dictates how a class acting as a Web API client should look like:

interface IEmployeeApiClient {
    get(callback:(data: IEmployee[]) 
=> void): void;
    getByID(id: number, callback: 
(data: IEmployee) => void): void;
    post(data: IEmployee, callback: 
(msg: string) => void);
    put(data: IEmployee, callback: 
(msg: string) => void);
    delete(id: number, callback: 
(msg: string) => void);
}

Notice the IEmployeeApiClient interface carefully. It contains five function signatures - get(), getByID(), post(), put(), and delete().

The get() function implementation is supposed to invoke the Get() action of the Employees Web API. The Employees Web API returns an array of employee objects. The get() function receives a callback function as a parameter. After invoking the Get() Web API action, the employees returned by the Web API are (IEmployee array) passed to this callback function. The callback function then displays them in a table. This arrangement separates Web API invoking logic from results displaying logic.

 The getByID() function is similar but also accepts employee ID through its id parameter. The callback passed to the getByID() receives a single IEmployee object.

The post() and put() functions take an IEmployee as a paremeter indicating an employee to be added or modified respectively. In this case, the callback receives a success / error message from the Web API.

The delete() function takes an employee ID to be deleted and after deleting it invokes the callback function by passing the success / error message received from the Web API.

All the five functions discussed above return void.

From the IEmployeeApiClient interface you know that we are going to need a set of callback functions that act on the data returned by the Employees Web API. These callback functions are wrapped inside a TypeScript class discussed later in this article. To dictate the structure of this class we create another interface - IEmployeeAppUi. This interface is shown below:

interface IEmployeeAppUi {
    getCallback(data: IEmployee[]): void;
    getByIDCallback(data: IEmployee): void;
    postCallback(msg: string): void;
    putCallback(msg: string): void;
    deleteCallback(msg: string): void;
}

The IEmployeeAppUi interface contains five methods namely getCallback(), getByIDCallback(), postCallback(), putCallback(), and deleteCallback(). The function signatures of these functions should look familiar to you since we discussed them along with IEmployeeApiClient interface.

So far so good. Now it's time to implement these interfaces in two classes namely EmployeeApiClient and EmployeeAppUi.

The skeleton of EmployeeApiClient class looks like this:

class EmployeeApiClient implements 
IEmployeeApiClient {

    private baseUrl: string;

    constructor(baseUrl: string) {
        this.baseUrl = baseUrl;
    }
    ...
    ...
}

The EmployeeApiClient class implements IEmployeeApiClient interface. Inside, we declare a private member named baseUrl. The baseUrl holds the base address of the Web API such as http://localhost:12345/Employees. TypeScript provides access modifiers such as private and public similar to C#. If you don't specify any access modifier by default the member is public. Here, we don't want baseUrl to be accessed outside of EmployeeApiClient and hence mark it private.

The EmployeeApiClient class has a constructor as indicated by a function named constructor. The constructor function accepts a baseUrl value and stores it in the private baseUrl property declared earlier.

We will now implement IEmployeeApiClient by adding various functions one-by-one.

The following code shows the implementation of get() function:

get(callback: (data: IEmployee[]) => void): 
void {
    this.callWebApi(this.baseUrl, 
HttpVerbs.GET, callback);
}

The get() function invokes a helper function called callWebApi() that makes a Web API call. The callWebApi() function as well as the Employees Web API is discussed later in this article. The callWebApi() function takes three parameters. The first parameter is the URL of the end-point of the Web API such as http://localhost:12345/Employees. The second parameter is the HTTP verb to be used. This parameter is the HttpVerb enumeration and here we pass GET. The third parameter is a callback function to be invoked once the Web API returns its response.

Let's take a look at the getByID() implementation:

getByID(id: number, 
callback: (data: IEmployee) => void): void {
    this.callWebApi(`${this.baseUrl}/${id}`,
        HttpVerbs.GET, callback, null, true);
}

The getByID() function also calls the callWebApi() helper function. Notice that we pass employee ID in the URL parameter after appending it to the baseUrl. In addition to HttpVerb and callback parameters two more parameters are passed. The fourth parameter is a object holding employee data used during POST and PUT operations. Here we pass it as null since GET operations don't need it. The fifth parameter is a boolean parameter indicating whether the operation is get "all" or get "by ID". The value of true indicates that it's a get by ID operation.

The post() function is shown below:

post(data: IEmployee, callback: 
(msg: string) => void): void {
    this.callWebApi(this.baseUrl, 
HttpVerbs.POST, callback,
        data);
}

The post() function takes two parameters - an employee object containing details of a new employee to be added. This object implements IEmployee. And a callback function. Inside, we call callWebApi() helper function as before. This time the HTTP verb used is POST and data object is the object holding employee details.

The put() function is similar to post() but uses PUT verb. The put() function is shown below:

put(data: IEmployee, callback: 
(msg: string) => void): void {
    this.callWebApi
(`${this.baseUrl}/${data.employeeID}`,
        HttpVerbs.PUT, callback, data);
}

Notice that the URL includes the employeeID value indicating the employee ID being modified.

The delete() function deletes an employee and is shown below:

delete(id: number, callback: 
(msg: string) => void): void {
    this.callWebApi
(`${this.baseUrl}/${id}`,
        HttpVerbs.DELETE, callback);
}

The delete() function accepts employee ID and callback. Inside, callWebApi() is called by passing URL and HttpVerb.DELETE.

Now that all the functions are implemented, it's time to add the callWebApi() helper function.

private callWebApi(url: string,
    verb: HttpVerbs,
    callback: any,
    data: IEmployee = null,
    isgetbyid: boolean = false): void {

    let xhr = new XMLHttpRequest();

    xhr.onload = function () {
        if (verb == HttpVerbs.GET) {
            if (isgetbyid) {
                let retValue: IEmployee;
                retValue = 
<IEmployee>JSON.parse(xhr.responseText);
                callback(retValue);
            }
            else {
                let retValue: IEmployee[];
                retValue = 
<IEmployee[]>JSON.parse(xhr.responseText);
                callback(retValue);
            }
        }
        else {
            let retValue: string;
            retValue = xhr.responseText;
            callback(retValue);
        }
    }

    xhr.onerror = function () {
        alert("Error while calling Web API");
    }

    xhr.open(verb, url);

    xhr.setRequestHeader("Content-Type", 
"application/json");

    if (data == null) {
        xhr.send();
    }
    else {
        xhr.send(JSON.stringify(data));
    }
}

The callWebApi() function is bit lengthy. So, take a look carefully.

There are five parameters. The url, verb, and callback parameters are required whereas data and isgetbyid are optional parameters.

Inside, the code creates an XMLHttpRequest object that is used to make Ajax request to the Employees Web API.

Notice the lines marked in bold letters. They indicate the methods and properties of the XMLHttpRequest object used by our code. They are discussed below:

  • onload
  • onerror
  • responseText
  • open()
  • setRequestHeader()
  • send()

The callback function indicated by the onload property is invoked upon successful completion of the Web API call. The onload function needs to read the response returned by the Web API. The response will be JSON data for Get() and GetByID() actions and string for other actions. Moreover, Get() is going to return JSON array whereas GetByID() is going to return just one employee object in JSON format. Notice the use of getbyid parameter to figure our which Web API action is being called.

The code inside the "if" block basically does this checking and accordingly retValue is either IEmployee[] or IEmployee. In the "else" block retValue is a string message returned by the Web API.

Notice the use of responseText property of XMLHttpRequest. This property contains the response sent by the Web API. If the expected response is JSON, we use JSON.parse() method to read it.

Once the response from the Web API is read the code invokes the callback function by passing the response to it.

The onerror callback function gets invoked when there is any error while calling the Web API. Here, it simply displays an alert to the user.

Then open() method of XMLHttpRequest is called by passing HTTP verb and the URL. The open() method initializes a request. The setRequestHeader() method sets the request Content-Type header to application/json because we want JSON to be the data format.

Finally, send() method of XMLHttpRequest is used to make the Web API request. You can also send data along with the request being made. In this example, POST and PUT requests carry an employee object along with the request body whereas GET and DELETE don't carry any data.

This completes the EmployeeApiClient class. But you won't be able to compile it successfully because EmployeeAppUi class and the Employees Web API aren't ready yet. You will do that in the next part of this series.

That's it for now! Keep coding!!


Bipin Joshi is an independent software consultant, trainer, author, yoga mentor, and meditation teacher. He has been programming, meditating, and teaching for 24+ years. He conducts instructor-led online training courses in ASP.NET family of technologies for individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Facebook  Twitter  LinkedIn  YouTube

Posted On : 20 April 2020


Tags : ASP.NET ASP.NET Core MVC .NET Framework C# Visual Studio


Subscribe to our newsletter

Get monthly email updates about new articles, tutorials, code samples, and how-tos getting added to our knowledge base.

  

Receive Weekly Updates