Angular  

Building Your First Angular Service (API Calls With HttpClient)

Introduction

Modern web applications rarely work in isolation. Almost every real application communicates with a backend to fetch, create, update, or delete data.

In Angular, the recommended way to interact with APIs is by using services, and the built-in HttpClient module makes performing HTTP operations simple and consistent.

In this article, we will learn step by step how to create a reusable Angular service to handle API calls, including:

  • Configuring HttpClient

  • Creating an Angular Service

  • Making GET, POST, PUT, DELETE calls

  • Handling errors properly

  • Using Observables

  • Displaying data in a UI

Real-World Scenario

Imagine you are building a small product management module. You need operations like:

  • Get all products

  • Get product by ID

  • Add new product

  • Update product

  • Delete product

If you implement API calls directly inside multiple components, your project quickly becomes difficult to manage.

Instead, you create a single Angular service called ProductService that handles all API operations in one place. This makes your project clean, scalable, and easier to maintain.

Step 1: Enable HttpClient in Angular

Open app.module.ts and import HttpClientModule:

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

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

Step 2: Generate a Service

Run the following command:

ng generate service services/product

Angular generates a file named:

product.service.ts

Step 3: Create the Service With API Methods

Example API URL:

https://localhost:5000/api/products

Service code

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

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

  private apiUrl = 'https://localhost:5000/api/products';

  constructor(private http: HttpClient) {}

  getProducts(): Observable<any> {
    return this.http.get(this.apiUrl);
  }

  getProductById(id: number): Observable<any> {
    return this.http.get(`${this.apiUrl}/${id}`);
  }

  addProduct(product: any): Observable<any> {
    return this.http.post(this.apiUrl, product);
  }

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

  deleteProduct(id: number): Observable<any> {
    return this.http.delete(`${this.apiUrl}/${id}`);
  }
}

Step 4: Use the Service in a Component

Example: Show products in UI.

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

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html'
})
export class ProductsComponent implements OnInit {

  products: any[] = [];

  constructor(private productService: ProductService) {}

  ngOnInit(): void {
    this.productService.getProducts().subscribe(data => {
      this.products = data;
    });
  }
}

Component Template

<h2>Product List</h2>

<ul>
  <li *ngFor="let product of products">
    {{ product.name }} - Rs. {{ product.price }}
  </li>
</ul>

Handling API Errors

Add RxJS catchError in service:

import { throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

getProducts(): Observable<any> {
  return this.http.get(this.apiUrl).pipe(
    catchError(error => {
      console.error('Error fetching products:', error);
      return throwError(() => error);
    })
  );
}

Using a Loading Indicator

You can manage component UI state:

loading = true;
errorMessage = '';

ngOnInit() {
  this.productService.getProducts().subscribe({
    next: (data) => {
      this.products = data;
      this.loading = false;
    },
    error: (err) => {
      this.errorMessage = 'Failed to load products';
      this.loading = false;
    }
  });
}

Example Template With UI Feedback

<p *ngIf="loading">Loading...</p>
<p *ngIf="errorMessage">{{ errorMessage }}</p>

<ul *ngIf="!loading && !errorMessage">
  <li *ngFor="let product of products">
    {{ product.name }}
  </li>
</ul>

Workflow Diagram

Component Requests Data
        |
        v
 Angular Service Calls API
        |
        v
 HttpClient Sends Request
        |
        v
 API Response Received
        |
        v
 Component Updates UI

Flowchart

START|
  v
Call Service Method|
  v
Send API Request via HttpClient
  |+--- Error? ---> Display Error Message|
  v
Update UI with Data
  |
 END

Best Practices

  • Keep all HTTP logic inside services.

  • Do not call APIs directly inside components.

  • Use models or interfaces instead of any.

  • Use environment variables for API URL.

  • Handle errors and display messages to users.

Common Mistakes and Solutions

MistakeWhy it HappensSolution
HttpClient not workingModule not importedAdd HttpClientModule
Values not showingForgetting subscribeAlways call .subscribe()
Duplicate codeMaking API calls in multiple componentsUse a shared service

Conclusion

Angular services allow you to create reusable and scalable logic for API access. With HttpClient, making requests becomes clean and efficient. Once this concept is mastered, you can move into:

  • Interceptors

  • Authentication and JWT tokens

  • Pagination and filtering

  • Caching responses

This is the foundation for a professional Angular application.