On this page
HTTP Client
Angular’s HttpClient provides a typed, Observable-based API for communicating with REST backends.
Setup
Register HttpClient in your app config:
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withFetch } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()) // Uses fetch API under the hood
]
};
GET Request
import { Component, inject, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { CommonModule } from '@angular/common';
interface Post {
id: number;
title: string;
body: string;
}
@Component({
selector: 'app-post-list',
standalone: true,
imports: [CommonModule],
template: `
@if (loading) { <p>Loading...</p> }
@for (post of posts; track post.id) {
<h2>{{ post.title }}</h2>
}
`
})
export class PostListComponent implements OnInit {
private http = inject(HttpClient);
posts: Post[] = [];
loading = false;
error = '';
ngOnInit() {
this.loadPosts();
}
loadPosts() {
this.loading = true;
this.http.get<Post[]>('https://jsonplaceholder.typicode.com/posts')
.subscribe({
next: data => {
this.posts = data.slice(0, 5);
this.loading = false;
},
error: err => {
this.error = 'Failed to load posts';
this.loading = false;
console.error(err);
}
});
}
}
POST, PUT, DELETE
@Injectable({ providedIn: 'root' })
export class PostService {
private http = inject(HttpClient);
private apiUrl = 'https://jsonplaceholder.typicode.com/posts';
getPosts() {
return this.http.get<Post[]>(this.apiUrl);
}
createPost(post: Omit<Post, 'id'>) {
return this.http.post<Post>(this.apiUrl, post);
}
updatePost(id: number, post: Partial<Post>) {
return this.http.put<Post>(`${this.apiUrl}/${id}`, post);
}
deletePost(id: number) {
return this.http.delete<void>(`${this.apiUrl}/${id}`);
}
}
Request Options
Pass headers, query params, and observe response details:
import { HttpParams, HttpHeaders } from '@angular/common/http';
const params = new HttpParams().set('page', '1').set('limit', '10');
const headers = new HttpHeaders({ Authorization: 'Bearer my-token' });
this.http.get<Post[]>('/api/posts', { params, headers });
Error Handling with catchError
Centralize error logic in a service:
import { catchError, throwError } from 'rxjs';
getPosts() {
return this.http.get<Post[]>(this.apiUrl).pipe(
catchError(err => {
console.error('API error:', err);
return throwError(() => new Error('Something went wrong'));
})
);
}
HTTP Interceptors
Attach auth tokens to every request:
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem('token');
return next(token
? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } })
: req);
};
// app.config.ts
provideHttpClient(withInterceptors([authInterceptor]))
Keep HTTP logic in services, not components — components subscribe and update the UI.