Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

CRUD Operation With Angular 5 HTTPClient and ASP.NET Core Web API

DZone's Guide to

CRUD Operation With Angular 5 HTTPClient and ASP.NET Core Web API

Interested in learning how to integrate one of the most popular APIs with one of the most popular web application development frameworks? Then read on for more!

· Integration Zone ·
Free Resource

SnapLogic is the leading self-service enterprise-grade integration platform. Download the 2018 GartnerMagic Quadrant for Enterprise iPaaS or play around on the platform, risk free, for 30 days.

HTTP is the messaging system between the client and the server. The client sends the request and the server responds with the proper message. Angular HTTP Client is the toolkit which enables us to send and receive data over RESTful HTTP endpoints. In Angular 4.3, this Angular HTTP API was provided, which is the extension to the existing API that provides some new features and added-in its own package of the @angular/common/http.

Let’s divide this article into two sections. The first will be the Angular and UI parts, the second will be on the server-side code which will hold the API part of the project.

Client-Side Setup

To make the HTTP client module available in the application, we must make sure it is included and configured properly in the application. Let’s see, step-by-step, how we can do this.

1. Import the HTTP client module into the application module or root module so that our root module is app.module.ts.

import {
    BrowserModule
} from '@angular/platform-browser';
import {
    NgModule
} from '@angular/core';
import {
    HttpClientModule
} from '@angular/common/http';
import {
    FormsModule
} from '@angular/forms'
import {
    AppComponent
} from './app.component';

@NgModule({
    declarations: [
        AppComponent,
    ],
    imports: [
        BrowserModule, HttpClientModule, FormsModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})

export class AppModule {}

Now that we have imported the HTTP Client in our application, we can use them in our component easily. For this demo, we are using 'Employee' as our entity and we are going to demo the GET, POST, PUT, and DELETE Requests. For this demo, let's add one component to our Angular application.

In my case, I have added the component Employee. The home component template for the component looks like below:

<div class="container">
 <h3>Employee List</h3>
  <table class="table table-condensed">
    <thead>
      <tr>
        <td>  &nbsp; </td>
        <td>  &nbsp;  </td>
        <td>  &nbsp;  </td>
        <td>  &nbsp;  </td>
        <td>  <a (click)="ShowRegForm(e)">Add New</a></td>
      </tr>
      <tr>
        <th>ID</th>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Email</th>
        <th>Edit</th>
      </tr>
    </thead>
    <tbody>
      <tr class="success" *ngFor="let e of employeelist ">
        <td> {{e.id}}</td>
        <td>{{e.fname}}</td>
        <td>{{e.lname}}</td>
        <td>{{e.email}}</td>
        <td><a (click)="ShowRegForm(e)">Edit</a></td>
        <td><a (click)="ShowRegFormForDelete(e)">Delete</a></td>
      </tr>
    </tbody>
  </table>
</div>

<hr >

<form #regForm="ngForm">
<div class="container" *ngIf="editCustomer">
 <h3>{{FormHeader}}</h3>
  <table class="table table-condensed">
    <tbody>
      <tr>
        <td>First Name</td>
        <td><input type="text" name="fname" [(ngModel)] ></td>
      </tr>
      <tr>
        <td>Last Name</td>
        <td><input type="text" name="lname" [(ngModel)]></td>
      </tr>
      <tr>
        <td> Email</td>
        <td><input type="text" name="email" [(ngModel)]></td>
      </tr>
      <tr>
        <td><input type="hidden" name="id" [(ngModel)]></td>
        <td><input type="button" value="Save" (click)="Save(regForm)"></td>
      </tr>
    </tbody>
  </table>
 </div>
</form>

Code Description

Here we have an HTML page which displays the list of the employees present in the database and which also gives the option to Add, Edit, List, and Delete entries.

Here, based on the input button, the form header will be set according to the operation, such as delete, add, and edit.

The next step is the component itself and the code we have for that.

1. Import Statements

import {
    Component,
    OnInit
} from '@angular/core';
import {
    NgForm
} from '@angular/forms'
import {
    FormsModule
} from '@angular/forms'
import {
    Observable
} from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';

import {
    EmployeeDataService
} from '../DataServices/EmployeeDataService';
import {
    employee
} from '../Models/Employee';

These are the basic imports, with some others added in, like the do, filter, and map imports. These are the operators which are used to transform the result that we get from the service.

Another section we have is the Data Service part and the Modal part. We also have EmployeeDataService in our TypeScript above, which we have created to handle the data related operations.

2. Constructor and Injecting the Data Service

Here we have used the Employee Data Service in our application. To use it, we have used the DI and injected it into constructor like below:

constructor(private dataservice: EmployeeDataService) // Available at imports
{  }

The next section is the code which we are using to call the data services:

ngOnInit() {
        this.dataservice.getEmployee().subscribe((tempdate) => {
            this.;
        }), err => {
            console.log(err);
        }
    }
    (employee) {
        this.;
        if (employee!) {
            this.SetValuesForEdit(employee)
        } else {
            this.ResetValues();
        }
    }
    (employee) {
        this.;
        if (employee!) {
            this.SetValuesForDelete(employee)
        }
    }
    (employee) {
        this..fname;
        this..lname;
        this..email;
        this..id;
        this.FormHeader = "Delete"
    }
//Function to set the values for edit form
(employee) {
    this..fname;
    this..lname;
    this..email;
    this..id;
    this.FormHeader = "Edit"
}
//Function to reset the values
ResetValues() {
    this.fname = "";
    this.lname = "";
    this.email = "";
    this.id = "";
    this.FormHeader = "Add"
}
//Common function for the Operation
Save(regForm: NgForm) {
    this.GetDummyObject(regForm);
    switch (this.FormHeader) {
        case "Add":
            this.Addemployee(this.Dummyemployee);
            break;
        case "Edit":
            this.UpdateEmployee(this.Dummyemployee);
            break;
        case "Delete":
            this.DeleteEmployee(this.Dummyemployee);
            break;
        default:
            break;
    }
}

GetDummyObject(regForm: NgForm): employee {
    this.Dummyemployee = new employee
    this.Dummyemployee..value.email;
    this.Dummyemployee..value.fname;
    this.Dummyemployee..value.lname;
    this.Dummyemployee..value.id;
    return this.Dummyemployee;
}
Addemployee(e: employee) {
    this.dataservice.AddEmployee(this.Dummyemployee).subscribe(res => {
        this.employeelist.push(res);
        alert("Data added successfully !! ")
        this.;
    }), err => {
        console.log("Error Occured " + err);
    }
}

UpdateEmployee(e: employee) {
    this.dataservice.EditEmployee(this.Dummyemployee).subscribe(res => {
        this.;
        this.dataservice.getEmployee().subscribe(res => {
            this.;
        });
        alert("Employee data Updated successfully !!")
    });
}

DeleteEmployee(e: employee) {
    this.dataservice.DeleteEmployee(this.Dummyemployee).subscribe(res => {
        this.;
        this.dataservice.getEmployee().subscribe(res => {
            this.;
        });
        alert("employee Deleted successfully !! ")
    });
}

We can see that we have called the getEmployee method from the ngOnInit event of the component instead of calling in the constructor. We have specifically done this to avoid any delay in loading the component.

Next, we have methods like AddEmployee()DeleteEmployee(), and UpdateEmployee() which are used for calling the data service methods from the application, like Add, Edit, and Delete Employees.

Other methods are the supplementary methods which are used to clear the inputs and set the object.

The next thing that we have used in our application is the Config.ts file. The code for this is as follows:

export const ROOT_URL:string="http://localhost:39029/api/"; 

Here in this code, we have defined the Root_URL as the constant which holds the value of the API address. Next is the model employee.ts which we use to map the data which we are sending and receiving from the API. The code snippet for this is below:

export interface employee {
    ID: string;
    Fname: string;
    Lname: string;
    Email: string;
}

//Main and most important part of the application is the Data service which we have used

//Code snippet for the same is as follows.

import {
    HttpClient,
    HttpParams,
    HttpHeaders
} from '@angular/common/http';
import {
    Observable
} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/retry';
import 'rxjs/add/observable/of';
import 'rxjs/Rx';

import {
    employee
} from '../Models/Employee';
import {
    ROOT_URL
} from '../Models/Config';
import {
    Injectable
} from '@angular/core';

@Injectable()
export class EmployeeDataService {
    employees: Observable < employee[] > ;
    newemployee: Observable < employee > ;
    constructor(private http: HttpClient) {

    }
    getEmployee() {
        return this.http.get < employee[] > (ROOT_URL + '/Employees')
    }
    AddEmployee(emp: employee) {
        const headers = new HttpHeaders().set('content-type', 'application/json');
        var body = {
            Fname: emp.Fname,
            Lname: emp.Lname,
            Email: emp.Email
        }
        return this.http.post < employee > (ROOT_URL + '/Employees', body, {
            headers
        })
    }

    EditEmployee(emp: employee) {
        const params = new HttpParams().set('ID', emp.ID);
        const headers = new HttpHeaders().set('content-type', 'application/json');
        var body = {
            Fname: emp.Fname,
            Lname: emp.Lname,
            Email: emp.Email,
            ID: emp.ID
        }
        return this.http.put < employee > (ROOT_URL + '/Employees/' + emp.ID, body, {
            headers,
            params
        })
    }

    DeleteEmployee(emp: employee) {
        const params = new HttpParams().set('ID', emp.ID);
        const headers = new HttpHeaders().set('content-type', 'application/json');
        var body = {
            Fname: emp.Fname,
            Lname: emp.Lname,
            Email: emp.Email,
            ID: emp.ID
        }
        return this.http.delete < employee > (ROOT_URL + '/Employees/' + emp.ID)
    }
}

This is the data service class which we use to call the API. Let's see the methods and code description of the methods that are present in this class.

1. To make the HTTP Client available in the class we have imported, we need to get the HTTP packages from the common/HTTP package as follows:

Import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http'; 

To break this down a bit:

HttpClient gives us the HTTP methods like GET, POST, PUT, etc.

HttpParams is used for sending the parameter to the methods like PUT and DELETE.

HttpHeaders is used to pass the headers which can be used to pass the values.

2. Next, as every call to the Http client methods returns the observable, we need to get the observable package and a transform method as well.

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/retry';
import 'rxjs/add/observable/of';
import 'rxjs/Rx';

3. Next, we need to bring the Employee model in our application, along with the App URL constant and @Injectable attribute, so that we can inject this class as a Dependency Injection into another class.

import {employee} from '../Models/Employee';
import {ROOT_URL} from '../Models/Config';
import { Injectable }   from '@angular/core';

4. After making the class injectable, we add the HttpClient service as a dependency in the application using Constructor. By doing this, we have created a private variable HTTP which is of type HttpClient.

The first method we will see is the method getEmployee(): 

getEmployee() {
    return this.http.get < employee[] > (ROOT_URL + '/Employees')
}

This method is returning the observable of employee after getting it from the API.

One thing to notice here is that we are directly mapping the response which we are getting from the API to employee[] so that HttpClient allows us to map the response as a typed response.

The next method we need to deal with is the AddEmployee method.

AddEmployee((emp: employee)); {
    const headers = new HttpHeaders().set("content-type", "application/json");
    var data = {
        Fname: emp.Fname,
        Lname: emp.Lname,
        Email: emp.Email
    };
    return (
        this.http.post < employee > (ROOT_URL + "/Employees", data, {
            headers
        })
    );
}

This method accepts the employee object, which is our model object, and receives input from the component.

In this method, we have used HttpHeaders to set the content type for the request, which is application/json. Next, we have converted the data from the employee object in the JSON and then passed to the POST method of HTTP.

The POST method has a signature like:

Post(URL,Data Body,{Option data like Headers}) 

Another operation is EditEmployee, which accepts the employee object as a parameter body of the method as follows:

EditEmployee(emp: employee) {
        const params = new HttpParams().set('ID', emp.ID);
        const headers = new HttpHeaders().set('content-type', 'application/json');
        var body = {
            Fname: emp.Fname,
            Lname: emp.Lname,
            Email: emp.Email,
            ID: emp.ID
        }
        return his.http.put < employee > (ROOT_URL + '/Employees/' + emp.ID, body, {
            headers,
            params
        })

In this method, we need the emp.ID as a parameter for the operation and we are passing it using the attribute HttpParams. We have set the headers to application/json and converted the object to JSON.

Next is the PUT method of HTTP, and it accepts the URL along with the body header and parameters.

The last method to complete our CRUD application is the DELETE Method, which has the following structure:

DeleteEmployee(emp: employee) {
    const params = new HttpParams().set('ID', emp.ID);
    const headers = new HttpHeaders().set('content-type', 'application/json');
    var body = {
        Fname: emp.Fname,
        Lname: emp.Lname,
        Email: emp.Email,
        ID: emp.ID
    }
    return this.http.delete < employee > (ROOT_URL + '/Employees/' + emp.ID)
}

Here, we again used the parameter for passing and used it to delete the record. To do so, we have set the headers and called the DELETE method of HTTP which will return the observable of the employee type. We can use this in the application.

This was about the Angular code which we have used, now let’s look at some of the Web API code that we will be using in our application.

For this, I have added new ASP.NET Core application enabling the Web API and, without going into the details of adding the Web API and rest of the stuff, I will demonstrate some basic settings we need to allow the Angular app to pull from the Web API and avoid any CORS issues that may arise for that. We can check the Startup.cs which is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.EntityFrameworkCore;

namespace AngularWebAPI {
    public class Startup {
        public Startup(IConfiguration configuration) {
            Configuration = configuration;
        }
        public IConfiguration Configuration {
            get;
        }

        // This method gets called by the runtime. Use this method to add services to the container.

        public void ConfigureServices(IServiceCollection services) {
            services.AddMvc();
            services.AddCors();
            services.AddDbContext < ApplicationDbContext > (options => options.UseSqlServer("Your Connection string"));
            services.AddCors(options => {
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

        public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();
            }
            app.UseCorsMiddleware();
            app.UseMvc();
            app.UseCors("CorsPolicy");
        }
    }
}

In this startup, we have added the MVC Entity Framework and other stuff to run the application. Along with this, we have added one policy for CORS which will allow us to make a request from any origin.

Also, we have added one middleware which will handle the incoming request CORS issues. The code for this is below:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

public class CorsMiddleware {
    private readonly RequestDelegate _next;

    public CorsMiddleware(RequestDelegate next) {
        _next = next;
    }

    public Task Invoke(HttpContext httpContext) {
        httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
        httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
        httpContext.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept");
        httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
        return _next(httpContext);
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.

public static class CorsMiddlewareExtensions {
    public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder) {
        return builder.UseMiddleware < CorsMiddleware > ();
    }
}

This is the middleware which adds the headers in the incoming request and adds it in the request pipeline.

In this API, we are using the Code First Approach of the Entity framework. Here, our model class will be employee, which will be like below:

namespace AngularWebAPI.Models {
    public class Employee {
        public int ID {
            get;
            set;
        }
        public string Fname {
            get;
            set;
        }
        public string Lname {
            get;
            set;
        }
        public string email {
            get;
            set;
        }
    }
}

Next, we need to add the controller that will serve as our Web API controller, and we can use this class to map all the operation and use them accordingly.

namespace AngularWebAPI.Controllers {
    [Produces("application/json")]
    [Route("api/Employees")]
    public class EmployeesController: Controller {
        private readonly ApplicationDbContext _context;

        public EmployeesController(ApplicationDbContext context) {
            _context = context;
        }

        // GET: api/Employees

        [HttpGet]

        public IEnumerable < Employee > Getemployee() {
            return _context.employee;
        }

        // GET: api/Employees/5

        [HttpGet("{id}")]

        public async Task < IActionResult > GetEmployee([FromRoute] int id) {
            if (!ModelState.IsValid) {
                return BadRequest(ModelState);
            }

            var employee = await _context.employee.SingleOrDefaultAsync(m => m.ID == id);

            if (employee == null) {
                return NotFound();
            }
            return Ok(employee);
        }

        // PUT: api/Employees/5

        [HttpPut("{id}")]

        public async Task < IActionResult > PutEmployee([FromRoute] int id, [FromBody] Employee employee) {
            if (!ModelState.IsValid) {
                return BadRequest(ModelState);
            }
            if (id != employee.ID) {
                return BadRequest();
            }

            _context.Entry(employee).State = EntityState.Modified;

            try {
                await _context.SaveChangesAsync();
            } catch (DbUpdateConcurrencyException) {
                if (!EmployeeExists(id)) {
                    return NotFound();
                } else {
                    throw;
                }
            }
            return NoContent();
        }

        // POST: api/Employees

        [HttpPost]

        public async Task < IActionResult > PostEmployee([FromBody] Employee employee) {
            if (!ModelState.IsValid) {
                return BadRequest(ModelState);
            }

            _context.employee.Add(employee);

            await _context.SaveChangesAsync();

            return CreatedAtAction("GetEmployee", new {
                id = employee.ID
            }, employee);
        }

        // DELETE: api/Employees/5

        [HttpDelete("{id}")]

        public async Task < IActionResult > DeleteEmployee([FromRoute] int id) {
            if (!ModelState.IsValid) {
                return BadRequest(ModelState);
            }
            var employee = await _context.employee.SingleOrDefaultAsync(m => m.ID == id);

            if (employee == null) {
                return NotFound();
            }

            _context.employee.Remove(employee);

            await _context.SaveChangesAsync();

            return Ok(employee);
        }
        private bool EmployeeExists(int id) {
            return _context.employee.Any(e => e.ID == id);
        }
    }
}

This is the Web API controller which we use for all the database operations. As we are using the database, we can apply the migrations and generate a table in the database.

Note: We can use a better approach for handling the database operations, like a repository and using DTO. This is just for the explanation and to check how it works.

This was about the use of HttpClient to read, add, delete, and update employee data in a database. We have used the ASP.NET Core Web API. For the Web API, we have added middleware to avoid CORS issues, and, in this, we have used the EF Code first approach for interacting with the database.

Source Code Can Be Found at the Following Locations

1. Angular Code

2. Web API

References

https://blog.angularindepth.com/the-new-angular-httpclient-api-9e5c85fe3361

https://medium.com/codingthesmartway-com-blog/angular-4-3-httpclient-accessing-rest-web-services-with-angular-2305b8fd654b

https://Angular.io

With SnapLogic’s integration platform you can save millions of dollars, increase integrator productivity by 5X, and reduce integration time to value by 90%. Sign up for our risk-free 30-day trial!

Topics:
angular 5 ,httpclient ,web api ,integration

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}