How to implement Angular Http using HttpClient Module in Angular 12 .?

Angular applications can communicate with any web server supporting HTTP, regardless of what server-side platform is used. Angular 4.3 introduces an Angular httpClient module to request a call to the HTTP request and we’ll learn how to use Angular HTTP methods.

We have few objectives in this tutorial, first we’ll look at overview of Angular HTTPClient module. Second, we will learn different HTTP methods, third how to use HTTP with promise and observable.

We can define HTTP requests in Services, services are user-defined classes used to access the database and from the server site and other activities.  The front-end can’t make a request directly to the database because of a security issue. Angular recommends only having template-specific codes in components. A component’s responsibility is to enrich the UI/UX in the Angular application and delegate business logic to services. Components are consumers of services.

What is Angular Httpclient Module

Angular supports asynchronous HTTP communications via the HttpClient service from the @angular/common/http package. For the HTTP request sent by the browser on behalf of an application, we need to import HttpClient Module to use the HTTP request.

The new HttpClient service is included in HttpClientModule and can be used to initiate HTTP requests and process responses within your application. Angular httpClient Module is an upgraded version of HTTP from @angular/http module with the following improvements:

  • JSON is an assumed default and no longer needs to be explicitly parsed.
  • Interceptors allow middleware logic to be inserted into the pipeline.
  • Immutable request/response objects progress events for both request upload and response download and more.

Step 1: Conifgure and setup Angular Http project

Let first create our Angular Http project by using the following command and we don’t have any dependency to another library for HTTP request. We need to create a service to make HTTP requests to a server and lastly create a few components to demonstrate HTTP requests.

ng new httpClientApp --routing
cd httpClientApp
ng generate service services/todos

<-- Add few component to demonstrate Angular Http post & other methods -->
ng generate component components/home
ng generate component components/todos
ng generate component components/home
ng generate component components/edit-todo
ng generate component components/new-todo
Angular http example
Screenshot of our apps on Angular httpClient

We have a few components, in the todos component will use the Angular HTTP GET method, in this component we have the HTTP DELETE method. In the new todo and edit todo components, we are demonstrating HTTP POST and PUt requests. The HTPP we can perform the following request.

MethodDescription
GETDoesn’t contain a request body. GET or retrieve a list of entities from the server.
POST Create a new entity to the server.
PUTOverride the whole entity.
PATCHReplace a subset of an entity.
DELETEDelete entity from the server.

In our app.routing.module.ts let add routing for our components.

...
const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'todos', component: TodosComponent },
  { path: 'todo/:id', component: EditTodoComponent },
];

...
export class AppRoutingModule { }

And in our app.component.html template, we have added a navigation bar using the bootstrap framework. If you want to know the best way to install and used bootstrap in Angular. Then check our previous articles on how to install ng-bootstrap in Angular.

Let edit the app.component.html template to add a nav bar.

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" routerLink="/">Home</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" routerLink="todos">Todos</a>
      </li>
    </ul>
  </div>
</nav>
<div class="container">
  <router-outlet></router-outlet>
</div>

Create a todo interface

In our HTTP request, we are performing a strict type request on different HTTP methods. For that, we need to create an interface of todo, let create folder models and add todo.model.ts file with the following type.

export interface ITodo {
    id?: string;
    task: string;
    status: string;
}

Import Angular HttpClient module

To make an HTTP call request we have to import the HttpClient module. We can import this module into the application in either the root module or one of the feature modules before HTTP. We will import this module and FormsModule in our root module i.e the app.module.ts file.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TodosComponent } from './components/todos/todos.component';
import { HttpClientModule } from '@angular/common/http';
import { NewTodoComponent } from './components/new-todo/new-todo.component';
import { EditTodoComponent } from './components/edit-todo/edit-todo.component';
import { FormsModule } from '@angular/forms';
import { HomeComponent } from './components/home/home.component';

@NgModule({
  declarations: [
    AppComponent,
    TodosComponent,
    NewTodoComponent,
    EditTodoComponent,
    HomeComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    FormsModule,
    NgbModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Setting up server for HTTP request

Setting up the server and adding data to the database will make our tutorial very long. We’ll use JSON Server to allow us to make fake HTTP requests without any coding and let install it globally.

npm install json-server

All the HTTP requests to JSON Server are the same as Node-based express-js.

Create Dummy data for HTTP Request

We have almost completed all configurations need for setting up HTTP requests and we have left with our data. Let create dummy data in src/data/todo.json and add the following data.

{
  "todos": [
    {
      "id": "1",
      "task": "Meditation at 7 am",
      "status": "pending"
    },
    {
      "id": "2",
      "task": "Task 4 creation of blog post",
      "status": "finished"
    },
    {
      "task": "Task 3 ",
      "status": "finished",
      "id": "3"
    },
    {
      "id": "4",
      "task": "Task 4 todo",
      "status": "pending"
    }
  ]
}

To request or access dummy data, we need to run our fake server using the following command in our project folder on the terminal.

json-server src/assets/data/todos.json

Note: We need to run the above command to make an HTTP request. Now you can access JSON data in our URL as follows.

Angular Json server

Step 2: Create a service to request HTTP request

We have to create a service class to request HTTP requests to a remote server. In the HTTP Service, we’ll encapsulate some logic that helps manage the list of todos into service, edit, delete and create new todos using the HttpClient service from Angular.

We have already created todo.service.ts in the app/services folder. We have to import HttpClient from HttpClientModule and inject the HttpClient dependency in the constructor.

import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs'
import { ITodo } from '../model/todo.model';
import { catchError } from 'rxjs/operators';

const URL_PREFIX = "http://localhost:3000";
@Injectable({
  providedIn: 'root'
})
export class TodosService {
  constructor(private http: HttpClient) { }

  getTodos(): Observable<Array<ITodo>> {
    return this.http.get<Array<ITodo>>(`${URL_PREFIX}/todos`,);
  }

  getTodo(id: string): Observable<ITodo> {
    return this.http.get<ITodo>(`${URL_PREFIX}/todos/${id}`);
  }


  addTodo(todo: ITodo) {
    return this.http.post(`${URL_PREFIX}/todos`, todo)
      .pipe(
        catchError((error: HttpErrorResponse) => {
          console.log(error.message);
          return throwError("Error while creating a todo" + error.message);
        }));
  }


  updateTodo(todo: ITodo, id: string): Observable<ITodo> {
    return this.http.put<ITodo>(`${URL_PREFIX}/todos/${id}`, todo)
      .pipe(
        catchError((error: HttpErrorResponse) => {
          // this.errorHandler.log("Error while updating a todo", error);
          console.log(error.message);
          return throwError("Error while updating a todo " + error.message);
        }));
  }

  patchTodo(todo: ITodo, id: string): Observable<ITodo> {
    return this.http.patch<ITodo>(`${URL_PREFIX}/todos/${id}`, todo)
      .pipe(
        catchError((error: HttpErrorResponse) => {
          console.log(error.message);
          return throwError("Error while updating a todo " + error.message);
        }));
  }

  deleteTodo(id: string) {
    return this.http.delete(`${URL_PREFIX}/todos/${id}`).pipe(
      catchError((error: HttpErrorResponse) => {
        console.log(error.message);
        return throwError("Error while deleting a todo " + error.message);
      }));
  }
}

In our service, we have performed all HTTP Requests, we have const URL_PREFIX containing the URL of our server.

Angular HTTP requests are asynchronous and we can handle asynchronous by three different approaches.

  1. Callbacks : Is not recommend and will not used it.
  2. Promises
  3. Observables.

Angular HTTP GET method

In our Angular service, we have used getTodos() observable to retrieve all todos from our server localhost:3000 or remote server. In our todo service, we have used the HttpClient object get method to get call HTTP requests.

Angular uses typescript which allows us to return explicitly type, in our HTTP GET we return observable of type ITodo array only. Uses of explicit type will reduce error.

Angular http get

Now in the todos component, we can inject our todos service and call getTodos() methods. This method in turn returns observable which we can subscribe in our consumer components. Let edit the todos.component.ts file.

import { Component, OnInit } from '@angular/core';
import { ITodo } from 'src/app/model/todo.model';
import { TodosService } from 'src/app/services/todos.service';

@Component({
  selector: 'app-todos',
  templateUrl: './todos.component.html',
  styleUrls: ['./todos.component.scss']
})
export class TodosComponent implements OnInit {
  todos: ITodo[] = [];

  constructor(private todoService: TodosService) { }

  ngOnInit(): void {
    this.todoService.getTodos()
      .subscribe((data: ITodo[]) => this.todos = data);
  }

  deleteTodo(todo: ITodo) {
    let id = todo.id ? todo.id : '';
    this.todoService.deleteTodo(id).subscribe(() => {
      alert('Delete todo : ');
    })
  }
}

In our todo component, we have injected Angular HTTP service and call both todos and delete methods. Subscribing to HTTP GET will return either list of todos or errors while calling a remote HTTP request.

Let edit the todos.component.html to loop through the todos array, and add a button to delete by sending the id of todo in the HTTP Delete method. We also have an edit button to route to the todo-edit component, where we can edit our todo.

<table class="table table-striped">
    <thead>
        <tr>
            <th scope="col">#</th>
            <th scope="col">Task</th>
            <th scope="col">Status</th>
            <th scope="col">Edit</th>
            <th scope="col">Delete</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let todo of todos; index as i">
            <th scope="row">{{ i + 1 }}</th>
            <td>{{ todo.task }}</td>
            <td>
                <span *ngIf="todo.status == 'finished'">
                    Completed
                </span>
                <span *ngIf="todo.status == 'pending'">
                    Pending
                </span>
            </td>
            <td>
                <button [routerLink]="['/todo/' + todo.id]">Edit</button>
            </td>
            <td>
                <i (click)="deleteTodo(todo)" class=" bi bi-trash icon-red"></i>
            </td>
        </tr>
    </tbody>
</table>

Angular HTTP GET method using observable and promise

In our previous example in Angular HTTP service, we have call HTTP GET on todos with only return type Observable. We can use Promise and Observable on HTTP GET, let edit our todos.service.ts file to add the following code.

import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, Observer, throwError } from 'rxjs'
import { Injectable } from '@angular/core';
import { catchError } from 'rxjs/operators';
import { ITodo } from '../models/todo.model';

const URL_PREFIX = "http://localhost:3000";
.....

  //HTTP GET with observable
  getTodosObservable(): Observable<Array<ITodo>> {
    return new Observable((observer: Observer<Array<ITodo>>) => {
      let results: Array<ITodo> = [];
      this.http.get<Array<ITodo>>(`${URL_PREFIX}/todos`)
        .subscribe((data: Array<ITodo>) => {
          data.map(i => {
            results.push(i)
          });
          observer.next(results);
          observer.complete();
        },
          // () => ({/** Error handling code goes here */ }),
          // () => ({/** Observable complete */ })
        );
    });
  }

 // HTTP GET with promise
  getPromiseTodos(): Promise<Array<ITodo>> {
    return new Promise<Array<ICountry>>((resolve) => {
      let results: Array<ITodo> = [];
      this.httpClient.get<Array<ITodo>>(`${URL_PREFIX}/todos`)
        .subscribe((data: Array<ITodo>) => {
            data.map(i => {
              results.push(i)
            });
            resolve(results);
          },
          () => ({/** Error handling code goes here */ }),
          () => ({/** Observable complete */ })
        );
    });
  }
}

Let us use observable on our consumer components, here we can use the async pipe on observable and let demonstrate it in our todos component.

import { Component, OnInit } from '@angular/core';
import { ITodo } from 'src/app/model/todo.model';
import { TodosService } from 'src/app/services/todos.service';

@Component({
  selector: 'app-todos',
  templateUrl: './todos.component.html',
  styleUrls: ['./todos.component.scss']
})
export class TodosComponent implements OnInit {
  todos$: Observable<Array<ITodo>> | undefined;

  constructor(private todoService: TodosService) {
    this.todos$ = this.todoService.getTodosObservable();
    // For promise http GET
    // this.todoService.getPromiseTodos()
    //.then((data: ICountry[]) => this.countries = data);
  }

Now in our todos template, we can use the async pipe on todos$ observable as follows.

...
 <tbody>
        <tr *ngFor="let todo of todos$ | async; index as i">
            <th scope="row">{{ i + 1 }}</th>
            <td>{{ todo.task }}</td>
            <td>
                <span *ngIf="todo.status == 'finished'">
                    Completed
                </span>
                <span *ngIf="todo.status == 'pending'">
                    Pending
                </span>
            </td>
            <td>
                <button [routerLink]="['/todo/' + todo.id]">Edit</button>
            </td>
            <td>
                <i (click)="deleteTodo(todo)" class=" bi bi-trash icon-red"></i>
            </td>
        </tr>
    </tbody>
...

Angular HTTP POST example

To add a new entity to our database server, we can use the HTTP POST method. In our new todo component, we are calling addTodo to add a new todo to our todos.json file.

Angular HTTP post example

We had already added HTTP POST to add new todo in our todos.service.ts file using the Angular HTTPClient object. On our consumer component, new-todo let’s add code to add new todo and form to accept data. In a real application, we don’t need to add an id, this is handle by the server but in our case, we are using a fake JSON server.

import { Component } from '@angular/core';
import { ITodo } from 'src/app/model/todo.model';
import { TodosService } from 'src/app/services/todos.service';

@Component({
  selector: 'app-new-todo',
  templateUrl: './new-todo.component.html',
  styleUrls: ['./new-todo.component.scss']
})
export class NewTodoComponent {

  constructor(private todoService: TodosService) { }

  addTodo(todo: ITodo) {
    this.todoService.addTodo(todo).subscribe((data: any) => {
      alert('Add new task successful' + data);
    })
  }
}

In the new.todo.component.html template add Angular form to accept data from users.

<div class=form-container>
    <h6>Add new todo</h6>
    <form #taskForm="ngForm" (ngSubmit)="addTodo(taskForm.value)">
        <div class="form-group">
            <label>ID</label>
            <input type="text" name="id" class="form-control" ngModel>
        </div>
        <div class="form-group">
            <label>Task name</label>
            <input type="text" name="task" class="form-control" ngModel>
        </div>

        <div class="form-group radio">
            <label>Status</label>
            <input type="radio" name="status" class="form-control" value="finished" 
             ngModel> Completed
            <input type="radio" name="status" class="form-control" value="pending" 
            ngModel> Pending
        </div>
        <div class="form-group">
            <button class="btn btn-primary" type="submit">Submit</button>
        </div>
    </form>
</div>

When we enter new todo and clicking on submit button will invoke addTodo which intern call HTTP POST to add new todo and return add todo.

Angular HTTP PUT example

At last, we can demonstrate HTTP PUT and PATCH, both are used to edit data in the database server. The PUT method will override the whole entity and PATCH will edit the subset of the entity.

Angular HTTP put exmple

When the user clicks on the edit button of corresponding todo in todo list, the Angular application will navigate to a todo-edit component by using http://localhost:4200/todo/2.

Once we are in the edit-todo component we can retrieve the corresponding todo by using its id from the URL and ActivatedRoute object. Clicking on the update button will invoke Angular HTTP PUT to override the existing todo with the new value.

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ITodo } from 'src/app/model/todo.model';
import { TodosService } from 'src/app/services/todos.service';

@Component({
  selector: 'app-edit-todo',
  templateUrl: './edit-todo.component.html',
  styleUrls: ['./edit-todo.component.scss']
})
export class EditTodoComponent implements OnInit {
  todo = {
    id: '',
    task: '',
    status: ''
  };

  constructor(
    private router: Router,
    private activatedRoute: ActivatedRoute,
    private todoService: TodosService
  ) { }

  ngOnInit(): void {
    let id = this.activatedRoute.snapshot.params['id'];
    if (id) {
      this.todoService.getTodo(id).subscribe((data: any) => {
        this.todo = {
          id: data.id,
          task: data.task,
          status: data.status
        }
      })
    }
  }


  updateTodo(todo: ITodo) {
    this.todoService.updateTodo(todo, this.todo.id)
    .subscribe((data) => {
      alert('Successful update');
      this.router.navigateByUrl('todos');
    })
  }

}

In our edit-todo template add the todo edit form, to allow the user new data for todo.

<div class=form-container>
    <h6>Edit Todo</h6>
    <form #taskForm="ngForm" (ngSubmit)="updateTodo(taskForm.value)">
        <div class="form-group">
            <label>Task name</label>
            <input type="text" name="task" class="form-control" [(ngModel)]="todo.task">
        </div>

        <div class="form-group radio">
            <label>Status</label>
            <input type="radio" name="status" class="form-control" value="finished" [(ngModel)]="todo.status">Completed
            <input type="radio" name="status" class="form-control" value="pending" [(ngModel)]="todo.status"> Pending
        </div>
        <div class="form-group float-right">
            <button class="btn btn-primary" type="submit">Update</button>
        </div>
    </form>
</div>

Conclusion
Angular httpClient methods allow us to communicate to a remote server through REST API. We can also use a third party like ngx-restangular to make HTTP requests to the server. It is best practice to keep HTTP requests code at service, and components are consumers of service. I have uploaded the above code in Github repository, if it is helpful then you check the code there.

Related Articles

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top