HttpClient & Fetching Data
Make HTTP requests from an Angular service using the built-in HttpClient, and expose the results through Observables.
Providing HttpClient
HttpClient must be enabled once, app-wide, via provideHttpClient() in your application config.
// app.config.tsimport { ApplicationConfig } from '@angular/core';import { provideHttpClient } from '@angular/common/http';
export const appConfig: ApplicationConfig = { providers: [provideHttpClient()],};Making a GET Request
A service wraps HttpClient calls, keeping components free of HTTP-specific logic. Every HttpClient method returns an Observable, not a Promise.
// posts.service.tsimport { Injectable, inject } from '@angular/core';import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })export class PostsService { private http = inject(HttpClient);
getPosts() { return this.http.get<Post[]>('/api/posts'); // returns Observable<Post[]> }}Consuming It in a Component
A component subscribes to the returned Observable to actually trigger the request and receive its result.
import { Component, OnInit, inject } from '@angular/core';import { CommonModule } from '@angular/common';import { PostsService } from './posts.service';
@Component({ selector: 'app-posts', standalone: true, imports: [CommonModule], template: ` <ul> <li *ngFor="let post of posts">{{ post.title }}</li> </ul> `,})export class PostsComponent implements OnInit { private postsService = inject(PostsService); posts: Post[] = [];
ngOnInit() { this.postsService.getPosts().subscribe(posts => { this.posts = posts; }); }}Assigning the Observable itself to a posts$ property and using {{ (posts$ | async) }} in the template (covered in the pipes lesson) avoids manually subscribing and unsubscribing entirely.
POST, PUT, and DELETE
createPost(title: string) { return this.http.post<Post>('/api/posts', { title });}
updatePost(id: number, title: string) { return this.http.put<Post>(`/api/posts/${id}`, { title });}
deletePost(id: number) { return this.http.delete<void>(`/api/posts/${id}`);}Typing the Response
Passing a generic type to any HttpClient method gives you full TypeScript autocomplete and checking on the response shape.
interface Post { id: number; title: string;}
getPosts() { return this.http.get<Post[]>('/api/posts');}Common Beginner Mistakes
HttpClient requests are lazy — nothing actually happens until you .subscribe() (or use the async pipe); an unused Observable never fires the request.
A component that manually calls .subscribe() should unsubscribe in ngOnDestroy, unless the Observable is guaranteed to complete on its own (like most single-response HTTP requests do).
FAQs
Observables support cancellation, retries, and powerful operator chaining (covered in the RxJS lessons) that Promises don't — a deliberate design choice for handling real-world HTTP concerns.
Yes — the firstValueFrom() (or lastValueFrom()) RxJS utility converts an Observable into a Promise, letting you await a single HTTP response if you prefer that style.
Summary
HttpClient gives you a typed, Observable-based way to talk to a backend, wrapped cleanly inside a service. Next, you'll go deeper into RxJS and Observables themselves.