Simulate a Backend API with Angular In-Memory Web API

Get Started

Before we dive in, make sure you have the following:

  • Node.js V10.x
  • Prior working knowledge of Angular
  • Prior working knowledge of TypeScript

Introducing Angular In-Memory Web API

The Angular In-Memory Web API is a library that intercepts Angular Http and HttpClient requests, redirecting them to an in-memory data store that you control in the frontend. With this library, you can seamlessly mimic delayed responses and perform tasks that would typically require a backend developer. However, it has limited capabilities and is not intended for production use.

Setting Up an Angular Project

We’ll use the Angular CLI tool to scaffold our project. First, check if you have the Angular CLI tool installed by running the following command in your terminal:

ng --version

If you don’t have it installed, run the following command:

npm install -g @angular/cli

Now, create a new Angular project with the following command:

ng new my-app

The Angular CLI will ask you for some details about the application you want to create. Answer “No” to the question about Angular routing, and accept the default choice (CSS) for the stylesheet format.

Setting Up Angular In-Memory Web API

Setting up Angular In-Memory Web API is easy and straightforward. First, install it as a dev dependency:

npm install angular-in-memory-web-api --save-dev

In the src/app directory, create a data.services.ts file and add the following code:

import { InMemoryDbService } from 'angular-in-memory-web-api';

export class DataService implements InMemoryDbService {
  createDb() {
    let products = [
      { id: 1, name: 'Product 1' },
      { id: 2, name: 'Product 2' },
      { id: 3, name: 'Product 3' }
    ];
    return { products };
  }
}

This code snippet creates an Angular service that implements the InMemoryDbService interface. The service then implements the createDb method, which creates an object in memory that represents our database.

Configuring the Backend API

Add the following to src/app/app.module.ts:

import { HttpClientModule } from '@angular/common/http';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
import { DataService } from './data.service';

@NgModule({
  imports: [
    HttpClientModule,
    HttpClientInMemoryWebApiModule.forRoot(DataService)
  ],
  //...
})
export class AppModule { }

We import HttpClientInMemoryWebApiModule and call its forRoot method, passing the DataService as a parameter. This ensures we avoid creating multiple instances of DataService.

Introducing the Angular HTTP Client

The Angular HTTP client is a built-in HTTP client of the Angular framework. It’s available as an injectable class, with methods to perform HTTP requests. To use it, add the following to src/app/app.module.ts:

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [ HttpClientModule ],
  //...
})
export class AppModule { }

Building a CRUD Application

Building CRUD applications is an excellent way to learn new tools and concepts in software development. We’ll create a demo CRUD application that creates, updates, and deletes products.

Product Interface

Create a product.model.ts file in the products directory with the following code:

export interface Product {
  id: number;
  name: string;
}

This defines a type interface for the structure of the product data we’ll be working with.

Communication with the API Backend

Create a product.service.ts file in the products directory and add the following code:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

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

  private apiUrl = '/api/products';

  constructor(private http: HttpClient) { }

  getProducts() {
    return this.http.get(this.apiUrl);
  }

  addProduct(product: Product) {
    return this.http.post(this.apiUrl, product);
  }

  removeProduct(id: number) {
    return this.http.delete(`${this.apiUrl}/${id}`);
  }

  updateProduct(id: number, product: Product) {
    return this.http.put(`${this.apiUrl}/${id}`, product);
  }

}

We import HttpClient from the Angular built-in HTTP package and inject it into the ProductService class. The getProducts method uses the HttpClient service to get the list of products from the database and returns an observable of them.

Subscribing to an Observable Stream

Update product-list.component.ts with the following code:

import { Component, OnInit } from '@angular/core';
import { ProductService } from './product.service';

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

  products: Product[];

  constructor(private productService: ProductService) { }

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

  getProducts() {
    this.productService.getProducts().subscribe(products => {
      this.products = products;
    });
  }

  addProduct(product: Product) {
    this.productService.addProduct(product).subscribe(() => {
      this.getProducts();
    });
  }

  removeProduct(id: number) {
    this.productService.removeProduct(id).subscribe(() => {
      this.getProducts();
    });
  }

  updateProduct(id: number, product: Product) {
    this.productService.updateProduct(id, product).subscribe(() => {
      this.getProducts();
    });
  }

}

The getProducts method subscribes to the getProducts method of ProductService and sets the result to the products property of the component. Similarly, the addProduct, removeProduct, and updateProduct methods subscribe to the respective methods of ProductService.

Rendering the Component

Add the following to products/product-list/productlist.component.html:

<ul>
  <li *ngFor="let product of products">
    {{ product.name }}
    <button (click)="removeProduct(product.id)">Remove</button>
  </li>
</ul>

<form (ngSubmit)="addProduct({ name: productName })">
  <input type="text" [(ngModel)]="productName">
  <button type="submit">Add</button>
</form>

The *ngFor directive is used to render a list of items based on a data source. In our case, we render product data for each of the product objects in our products array.

Final Touches

Update app.component.html as follows:

<app-product-list></app-product-list>

Also, update app.module.ts as follows:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ProductListComponent } from './products/product-list/product-list.component';
import { ProductService } from './products/product.service';

@NgModule({
  declarations: [ AppComponent, ProductListComponent ],
  imports: [ BrowserModule ],
  providers: [ ProductService ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

Run the ng serve command again and open your browser on http://localhost:4200/. You should now see your CRUD application in action!

Leave a Reply