Consuming Restful API in angular

In continuation to our previous example on CRUD Operations using primeng datatable and Material Design, we will now look at how to call REST APIs using angular.

Step 1: REST API

We have our REST API developed using java. Below is the code which exposes TODO services to end users. It supports GET,POST,PUT,DELETE operations on resources.

package com.myjavablog.controller;

import com.myjavablog.entity.Todo;
import com.myjavablog.entity.User;
import com.myjavablog.repository.TodoRepository;
import com.myjavablog.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@CrossOrigin
@RestController
@RequestMapping("/api")
public class TodoController {

    @Autowired
    private TodoRepository todoRepository;

    @GetMapping("/todos")
    public List<Todo> getTodos(){
        return todoRepository.findAll();
    }

    @GetMapping("/todo/{id}")
    public Optional<Todo> getTodo(@PathVariable Long id){
        return todoRepository.findById(id);
    }

    @DeleteMapping("/todo/{id}")
    public boolean deleteTodo(@PathVariable Long id){
        todoRepository.deleteById(id);
        return true;
    }

    @PostMapping("/todo")
    public Todo createTodo(@RequestBody Todo todo){
        return todoRepository.save(todo);
    }

    @PutMapping("/todo")
    public Todo updateTodo(@RequestBody Todo todo){
        return todoRepository.save(todo);
    }

}

Entire code for this Todo REST API can be downloaded from below github link –

Step 2: How to call REST API from Angular

As we have seen in my previous post , we have written a service in angular to call the REST api’s . Below is the code to call the REST API from angular-

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { map, catchError, tap, retry } from 'rxjs/operators';
import { Todo } from './../domain/Todo';

@Injectable({
  providedIn: 'root'
})
export class TodoService {

  endpoint = 'http://localhost:8081/api';

  constructor(private http: HttpClient) {
  }

  // Http Options
  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  }

  // To Get List Of Todos
  getTodoList(): Observable<any> {
    return this.http.get(this.endpoint + '/todos')
      .pipe(
        retry(1),
        catchError(this.handleError)
      );
  }

  // HttpClient API get() method => Fetch Todo
  getTodo(id): Observable<Todo> {
    return this.http.get<Todo>(this.endpoint + '/todos/' + id)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // HttpClient API post() method => Create Todo
  createTodo(todo): Observable<Todo> {
    return this.http.post<Todo>(this.endpoint + '/todo', JSON.stringify(todo), this.httpOptions)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // HttpClient API put() method => Update Todo
  updateTodo(id, todo): Observable<Todo> {
    return this.http.put<Todo>(this.endpoint + '/todo' , JSON.stringify(todo), this.httpOptions)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // HttpClient API delete() method => Delete Todo
  deleteTodo(id):Observable<Todo[]> {
    console.log("Delete id "+ id);
    return this.http.delete<Todo[]>(this.endpoint+ '/todo/' + id);

  }

  // Error handling 
  handleError(error) {
    let errorMessage = '';
    if (error.error instanceof ErrorEvent) {
      // Get client-side error
      errorMessage = error.error.message;
    } else {
      // Get server-side error
      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    window.alert(errorMessage);
    return throwError(errorMessage);
  }
}

We are injecting private http: HttpClient object which is required to make REST API calls. I have hosted REST api on endpoint = ‘http://localhost:8081/api’ , now this endpoint is used to make all rest calls.

Here for all REST calls ,we are returning Observable objects. These methods are getting called from components where these returned objects gets subscribed.Below is the component from which this TodoService is getting called –

import { Component, OnInit } from '@angular/core';
import { TodoService } from 'src/app/services/todo.service';
import { Router } from '@angular/router';
import { map, catchError, tap, retry } from 'rxjs/operators';
import { NotifierService } from 'angular-notifier';
import { Todo } from 'src/app/domain/Todo';
import { SelectItem } from 'primeng/primeng';

@Component({
  selector: 'todo-list',
  templateUrl: './todo.component.html',
  styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
  cols: any[];
  todos: Todo[];
  displayedColumns: string[] = ['Task Name', 'Task Description', 'Status', 'action'];

  displayTodoList = true;
  displayTodoAdd = false;
  displayTodoEdit = false;

  constructor(private todoService: TodoService, private router: Router, private notifier: NotifierService) {
  }

  ngOnInit() {
    this.displayTodoList = true;
    this.displayTodoAdd = false;
    this.displayTodoEdit = false;

    console.log("From Init = " + this.displayTodoList + "  " + this.displayTodoAdd);
    this.getTodoList().subscribe((data) => { this.todos = data });

    this.cols = [
      { field: 'name', header: 'Task Name' },
      { field: 'desc', header: 'Task Description' },
      { field: 'status', header: 'Status' },
      { field: 'action', header: 'Action' }
    ];

    this.statusValues = [
      { label: 'Done', value: 'Done' },
      { label: 'Pending', value: 'Pending' },
      { label: 'Cancelled', value: 'Cancelled' }
    ];
  }

  // To Get List Of Todos
  getTodoList() {
    return this.todoService.getTodoList();
  }

  // To Get Todo
  getTodo(todoId) {
    return this.todoService.getTodo(todoId);
  }

  // To Edit Todo
  editTodo(todoId) {
    this.displayTodoList = false;
    this.displayTodoEdit = true;
    this.router.navigate([`/todo-edit/${todoId}`]);
  }

  //Delete Todo
  deleteTodo(todoId) {
    console.log("Delete id" + todoId);
    this.todoService.deleteTodo(todoId).subscribe((data) => {
      console.log("success");
      this.notifier.notify("success", "Task deleted successfully!!");
    });
    this.ngOnInit();
    this.router.navigate([`/`]);
  }

  //add Todo
  addTodo() {
    console.log("Before = " + this.displayTodoList + "  " + this.displayTodoAdd);
    this.displayTodoList = false;
    this.displayTodoAdd = true;
    console.log("After =" + this.displayTodoList + "  " + this.displayTodoAdd);
  }

  hideTodoAdd(event) {
    console.log("Event emiited " + event);
    this.displayTodoList = true;
    this.displayTodoAdd = event;
  }

  clonedTodos: { [s: string]: Todo; } = {};
  statusValues: SelectItem[];

  onRowEditInit(todo: Todo) {
    this.clonedTodos[todo.id] = { ...todo };
  }

  onRowEditSave(todo: Todo) {
    this.todoService.updateTodo(todo.id, todo).subscribe((data) => {
      console.log("success");
      this.notifier.notify("success", "Task updated successfully!!");
    });
  }

  onRowEditCancel(todo: Todo, index: number) {
    this.todos[index] = this.clonedTodos[todo.id];
    delete this.clonedTodos[todo.id];
  }
}

We have injected private todoService: TodoService via constructor and called its methods from TodoComponent .

What is observable and subscriber?

Observables – They provide support for passing messages between publishers and subscribers in your application. Observables offer significant benefits over other techniques for event handling, asynchronous programming, and handling multiple values.

Observables are declarative—that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. The subscribed consumer then receives notifications until the function completes, or until they unsubscribe.

  // To Get List Of Todos
  getTodoList(): Observable<any> {
    return this.http.get(this.endpoint + '/todos')
      .pipe(
        retry(1),
        catchError(this.handleError)
      );
  }

Subscribe – As a publisher, you create an Observable instance that defines a subscriber function. This is the function that is executed when a consumer calls the subscribe() method. The subscriber function defines how to obtain or generate values or messages to be published.

To execute the observable you have created and begin receiving notifications, you call its subscribe() method, passing an observer. This is a JavaScript object that defines the handlers for the notifications you receive. The subscribe() call returns a Subscription object that has an unsubscribe() method, which you call to stop receiving notifications.

this.getTodoList().subscribe((data) => { this.todos = data });

Code for this example can be downloaded from below links –

Leave a Comment

Bitnami