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!