Angular applications communicate with backend services through HttpClient from @angular/common/http. Configure the client for your Angular version, inject it into a service, and call methods such as get() or post(). Those methods return RxJS Observables; subscribing sends the request. Angular’s current setup guide says HttpClient is available for injection by default in Angular v21 and later, so setup depends on the version and application architecture.
Configure HttpClient for your Angular application
For current provider-based applications, configure provideHttpClient() in the application’s providers. Angular v21 and later make HttpClient available for injection by default, but projects on other versions should follow the setup guidance for their release rather than assume the same default. The setup guide covers provider-based and NgModule-based configurations: Angular: Setting up HttpClient.
The default client uses the fetch backend and includes default XSRF protection. Fetch is the recommended choice for server-side rendering (SSR); Angular warns against XHR in SSR and describes server-side XHR support as deprecated and intended for removal in Angular 23. Do not switch to XHR for ordinary requests. Use it only when you specifically need upload-progress events, which the default fetch backend cannot provide.
Make a request from a service
Keep backend access in a service so components can use application-level operations rather than construct HTTP requests themselves. Inject HttpClient, then call the method that matches the operation. Angular’s API includes methods such as get(), post(), put(), and delete(); each returns an Observable. See Angular: HTTP Client overview and Angular: Making requests.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problems#1 Best Overall
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
interface User {
id: number;
name: string;
}
@Injectable({ providedIn: 'root' })
export class UsersService {
private readonly http = inject(HttpClient);
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users');
}
createUser(user: User): Observable<User> {
return this.http.post<User>('/api/users', user);
}
}
The generic type argument describes the expected response shape for TypeScript; it does not validate the data returned by the server at runtime. Handle request errors where the application can respond appropriately, such as in the service or the consuming component, rather than assuming a successful response.
Subscribe deliberately: that is when the request is sent
Creating or returning the Observable does not itself send the HTTP request. A subscription triggers it, and each independent subscription to the request Observable can send another backend request. This matters when multiple parts of the application subscribe to the same service method or when a template and component code both initiate work. Arrange subscriptions so that a request is made at the intended time and avoid duplicate subscriptions when only one response is needed. If a result genuinely needs to be reused, choose an explicit sharing or caching strategy appropriate to the application.
Rank #2
Choose what the caller observes
By default, an HTTP method emits the response body, which is sufficient for most service operations. If the caller needs status or headers as well, set observe: 'response'. If it needs lifecycle or progress events, request the event stream and enable progress reporting. Progress reporting is disabled by default and has a performance cost; upload progress is unavailable with the default fetch backend. When upload progress is a requirement, configure XHR with withXhr(). The options and event behavior are described in Angular’s request guide.
Use interceptors for cross-cutting behavior
Interceptors are suitable for behavior shared across requests, such as adding API authentication headers, logging, caching, retry logic, or deadlines. Angular supports functional and DI-based interceptors, but recommends functional interceptors because their behavior is more predictable, particularly in complex configurations. They run in the configured order, so that order should reflect dependencies between shared behaviors. Keep operation-specific business logic in the service method that owns the request rather than moving it into global middleware. See Angular: Intercepting requests and responses.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallRank #3
Test requests without a live backend
Angular’s HTTP testing backend allows a test to capture requests, inspect their details, and provide a response or error. Configure the testing providers, inject HttpTestingController, trigger the application action, expect the request, make assertions, and flush the result. Check that no unexpected requests remain outstanding.
import { provideHttpClient } from '@angular/common/http';
import {
HttpTestingController,
provideHttpClientTesting,
} from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
describe('UsersService', () => {
let service: UsersService;
let httpTesting: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideHttpClient(),
provideHttpClientTesting(),
UsersService,
],
});
service = TestBed.inject(UsersService);
httpTesting = TestBed.inject(HttpTestingController);
});
afterEach(() => {
httpTesting.verify();
});
it('requests users', () => {
let users: User[] | undefined;
service.getUsers().subscribe(value => users = value);
const request = httpTesting.expectOne('/api/users');
expect(request.request.method).toBe('GET');
request.flush([{ id: 1, name: 'Ada' }]);
expect(users).toEqual([{ id: 1, name: 'Ada' }]);
});
});
When the test configures client features such as interceptors, provide provideHttpClient(...) before provideHttpClientTesting(). The testing provider replaces parts of the client configuration, so reversing the order can remove the features the test intends to exercise. See Angular: Testing HTTP requests.
Quick Recap
Rank #4
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




