Skip to main content

HTTP Client & Observables

HTTP Client Setup

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

// main.ts
bootstrapApplication(AppComponent, {
providers: [provideHttpClient()]
});

Basic HTTP Requests

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

@Injectable({ providedIn: 'root' })
export class UserService {
http = inject(HttpClient);
apiUrl = 'https://api.example.com/users';

// GET
getUsers() {
return this.http.get<User[]>(this.apiUrl);
}

// GET by ID
getUser(id: number) {
return this.http.get<User>(`${this.apiUrl}/${id}`);
}

// POST
createUser(user: User) {
return this.http.post<User>(this.apiUrl, user);
}

// PUT
updateUser(id: number, user: User) {
return this.http.put<User>(`${this.apiUrl}/${id}`, user);
}

// PATCH
patchUser(id: number, changes: Partial<User>) {
return this.http.patch<User>(`${this.apiUrl}/${id}`, changes);
}

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

Using in Component

@Component({
selector: 'app-user-list',
template: `
<div *ngFor="let user of users$ | async">
{{ user.name }}
</div>
`
})
export class UserListComponent {
userService = inject(UserService);
users$ = this.userService.getUsers();

// Or with subscribe
users: User[] = [];

ngOnInit() {
this.userService.getUsers().subscribe({
next: (data) => this.users = data,
error: (err) => console.error(err),
complete: () => console.log('Complete')
});
}
}

HTTP Headers & Params

import { HttpHeaders, HttpParams } from '@angular/common/http';

// Headers
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
});

this.http.get(url, { headers });

// Query params
const params = new HttpParams()
.set('page', '1')
.set('limit', '10')
.set('sort', 'name');

this.http.get(url, { params });
// GET /api/users?page=1&limit=10&sort=name

// Or object syntax
this.http.get(url, {
params: { page: '1', limit: '10' }
});

Interceptors

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

export const authInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem('token');

if (token) {
req = req.clone({
setHeaders: { Authorization: `Bearer ${token}` }
});
}

return next(req);
};

// Provide in main.ts
provideHttpClient(
withInterceptors([authInterceptor])
);

Error Handling

import { catchError, throwError } from 'rxjs';

getUsers() {
return this.http.get<User[]>(this.apiUrl).pipe(
catchError(error => {
console.error('Error:', error);
return throwError(() => new Error('Failed to load users'));
})
);
}

// In component
this.userService.getUsers().subscribe({
next: data => this.users = data,
error: err => this.errorMessage = err.message
});

Retry & Timeout

import { retry, timeout } from 'rxjs/operators';

getUsers() {
return this.http.get<User[]>(this.apiUrl).pipe(
timeout(5000), // 5 seconds
retry(3), // Retry 3 times on failure
catchError(this.handleError)
);
}

Observable Operators

import { map, filter, tap } from 'rxjs/operators';

// Transform data
getActiveUsers() {
return this.http.get<User[]>(this.apiUrl).pipe(
map(users => users.filter(u => u.active)),
tap(users => console.log('Active users:', users))
);
}

// Chain requests
getUserWithPosts(userId: number) {
return this.http.get<User>(`/users/${userId}`).pipe(
switchMap(user =>
this.http.get<Post[]>(`/posts?userId=${userId}`).pipe(
map(posts => ({ user, posts }))
)
)
);
}

Combining Observables

import { forkJoin, combineLatest } from 'rxjs';

// Wait for all to complete
loadData() {
forkJoin({
users: this.http.get<User[]>('/users'),
posts: this.http.get<Post[]>('/posts'),
comments: this.http.get<Comment[]>('/comments')
}).subscribe(({ users, posts, comments }) => {
// All data loaded
});
}

// Emit when any changes
combineLatest([
this.http.get<User[]>('/users'),
this.http.get<Post[]>('/posts')
]).subscribe(([users, posts]) => {
// Process combined data
});

Best Practices

  • Always unsubscribe or use async pipe
  • Use interceptors for auth, logging, errors
  • Type your HTTP responses
  • Handle errors gracefully
  • Use retry for transient failures
  • Cancel requests with takeUntil()