HttpClient with Angular 13

Updated : 23/12/21 danny

What are we going to do?

We will add in our project the HttpClient mechanism to communicate with an HTTP server.
We will use the Angular version 13.1.1 javascript framework.

This is Step 6 of our  Angular guide which will allow us to obtain a PWA Web Application.
We will use an existing project whose characteristics are

  • Generated with Angular CLI
  • Routing
  • Lazy Loading
  • Framework CSS Bootstrap
  • Server Side Rendering

All created sources are indicated at the end of the tutorial.

The application is at the following address


Installation

Our Angular application represents our Frontend.
We will use the Httpclient module from angular to access a REST API that will represent our Backend.

The object of this tutorial is not to develop a backend, so we will arbitrarily choose an API available on the web.

JSONPlaceholder is a free REST API ideal for tutorials.
It is accessible with the following link https://jsonplaceholder.typicode.com/

The steps will be as follows

  • Create an items module
  • Change the visual interface of the frontend
  • Routing
  • Adapt the module to use the REST API

Let's start by creating our Items module, this one being specific to our application will be created in the modules/application directory.


# Création du module items
ng generate component modules/application/items --module=app
ng generate module modules/application/items --routing --module=app

# Création du module items (Méthode 2)
ng g c modules/application/items --module=app
ng g m modules/application/items --routing --module=app

The modules/application directory is automatically created by Angular CLI


Let's modify the following files

  • app-routing.module.ts
  • app.module.ts
  • home.component.html
  • home.component.css
  • items-routing.module.ts
  • items.module.ts
src/app/app-routing.module.ts
  {
    path: 'httpclient',
    loadChildren: () => import('./modules/application/items/items.module')
      .then(mod => mod.ItemsModule)
  },
src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { HomeComponent } from './modules/general/home/home.component';
import { NotFoundComponent } from './modules/general/not-found/not-found.component';
import { AppRoutingModule } from './app-routing.module';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    NotFoundComponent,
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'angular-starter' }),
    AppRoutingModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
src/app/modules/application/items/items-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { ItemsComponent } from './items.component';

const routes: Routes = [
  { path: '', component: ItemsComponent },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class ItemsRoutingModule { }
src/app/modules/application/items/items.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { ItemsComponent } from './items.component';
import { ItemsRoutingModule } from './items-routing.module';

@NgModule({
  imports: [
    CommonModule,
    ItemsRoutingModule
  ],
  exports: [
    ItemsComponent
  ],
  declarations: [
    ItemsComponent
  ],
  providers: [
  ],
})
export class ItemsModule { }


At this point we can test the debug script to control the architecture of our project.
npm run start


Integration

All that remains is to integrate the httpclient management into our Items part.

To respect the Angular best practices all the features will be added in the app/modules/items directory.
We will create a service to manage access to the API.

The steps are as follows.

  • Create a service via an items.service.ts file
  • Edit the items.service.ts file to access the API
  • Edit the file items.component.ts to call the service
  • Modify the file items.module.ts to call the required angular module
  • Edit the test files items.component.spec.ts and items.service.spec.ts
  • Edit the items.component.html file to customize the result display


Let's start by creating the service with the corresponding angular-cli command and then modify the mentioned files.


# Création du service items
ng generate service modules/application/items/items

# Création du service items (Méthode 2)
ng g s modules/application/items/items
src/app/modules/application/items/items.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';

const httpOptions = {
  headers: new HttpHeaders(
    {
      'Content-Type': 'application/json',
    }
  )
};

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

  constructor(private http: HttpClient) { }

  getItems(url: string): Observable<object> {
    return this.http.get(url, httpOptions);
  }

}
src/app/modules/application/items/items.component.ts
import { Component, OnInit } from '@angular/core';
import { ItemsService } from './items.service';

@Component({
  selector: 'app-items',
  templateUrl: './items.component.html',
  styleUrls: ['./items.component.css']
})
export class ItemsComponent implements OnInit {

  items: any;
  loaded: boolean;
  constructor(
    private itemsService: ItemsService) {
    this.loaded = false;
  }

  ngOnInit(): void {
    this.getUsers();
  }

  getUsers(): void {
    this.loaded = false;
    this.itemsService.getItems('https://jsonplaceholder.typicode.com/users')
      .subscribe(
        items => {
          this.items = items;
          this.loaded = true;
        });
  }

  resetUsers(): void {
    this.items = null;
    this.loaded = true;
  }

}
src/app/modules/application/items/items.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { ItemsComponent } from './items.component';
import { ItemsRoutingModule } from './items-routing.module';
import { HttpClientModule } from '@angular/common/http';
import { ItemsService } from './items.service';

@NgModule({
  imports: [
    CommonModule,
    ItemsRoutingModule,
    HttpClientModule
  ],
  exports: [
    ItemsComponent
  ],
  declarations: [
    ItemsComponent
  ],
  providers: [ItemsService
  ],
})
export class ItemsModule { }
src/app/modules/application/items/items.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientModule } from '@angular/common/http';
import { ItemsComponent } from './items.component';

describe('ItemsComponent', () => {
  let component: ItemsComponent;
  let fixture: ComponentFixture<ItemsComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [
        HttpClientModule
      ],
      declarations: [ItemsComponent]
    }).compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(ItemsComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});
src/app/modules/items/items.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { HttpClientModule } from '@angular/common/http';
import { ItemsService } from './items.service';

describe('ItemsService', () => {
  let service: ItemsService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientModule
      ]
    });
    service = TestBed.inject(ItemsService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});
src/app/modules/items/items.component.html
<div class="row pb-4">

    <div class="col-12 col-sm-12 col-md-3 col-lg-3 col-xl-3">
      <div class="row pb-4">
        <div class="card" style="width: 18rem;">
          <div class="card-body">
            <h5 class="card-title">Feature : HttpClient</h5>
            <hr>
            <p class="card-text">Use HtppClient</p>
            <button type="button" class="btn btn-primary mr-4" (click)="getUsers()">Get</button>
            <button type="button" class="btn btn-primary" (click)="resetUsers()">Reset</button>
          </div>
        </div>
        <div *ngIf="!loaded">
          <div class="spinner-grow text-primary" role="status">
            <span class="sr-only">Loading...</span>
          </div>
          <div class="spinner-grow text-secondary" role="status">
            <span class="sr-only">Loading...</span>
          </div>
          <div class="spinner-grow text-success" role="status">
            <span class="sr-only">Loading...</span>
          </div>
          <div class="spinner-grow text-danger" role="status">
            <span class="sr-only">Loading...</span>
          </div>
          <div class="spinner-grow text-warning" role="status">
            <span class="sr-only">Loading...</span>
          </div>
          <div class="spinner-grow text-info" role="status">
            <span class="sr-only">Loading...</span>
          </div>
          <div class="spinner-grow text-dark" role="status">
            <span class="sr-only">Loading...</span>
          </div>
        </div>
      </div>
    </div>
  
    <div class="col-12 col-sm-12 col-md-8 col-lg-8 col-xl-8">
      <div class="row">
        <div class="table-responsive httpclient-table blue-gradient" *ngIf="loaded">
          <table class="table table-hover table-striped table-responsive-md">
            <thead>
              <tr>
                <th scope="col">name</th>
                <th scope="col">username</th>
                <th scope="col">email</th>
              </tr>
            </thead>
            <tbody>
              <tr *ngFor="let item of items">
                <td>{{item.name}}</td>
                <td>{{item.username}}</td>
                <td>{{item.email}}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
  
  </div>

Error

Let's do a ssr compilation

  • npm run build:ssr
  • npm run serve:ssr

If we type the following address 

  • http://localhost:4000/httpclient

We get an error on the server

  • ReferenceError: XMLHttpRequest is not defined

To solve this error, we need to move httpclientmodule from items.module.ts to app.module.ts

src/app/modules/application/items/items.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { ItemsComponent } from './items.component';
import { ItemsRoutingModule } from './items-routing.module';
import { ItemsService } from './items.service';

@NgModule({
  imports: [
    CommonModule,
    ItemsRoutingModule,
  ],
  exports: [
    ItemsComponent
  ],
  declarations: [
    ItemsComponent
  ],
  providers: [ItemsService],
})
export class ItemsModule { }
src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { HomeComponent } from './modules/general/home/home.component';
import { NotFoundComponent } from './modules/general/not-found/not-found.component';
import { AppRoutingModule } from './app-routing.module';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    NotFoundComponent,
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'angular-starter' }),
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Conclusion


All you need to do is test the various Angular scripts.


# Development
npm run start
http://localhost:4200/

# Tests
npm run lint
npm run test
npm run e2e

# AOT compilation
npm run build
http-server -p 8080 -c-1 dist/browser
http://localhost:8080/

# SSR compilation
npm run build:ssr
npm run serve:ssr
http://localhost:4000/