Angular's HTTP client provides a powerful, feature-rich solution for making HTTP requests with full TypeScript support, interceptors, error handling, request/response transformation, and comprehensive testing utilities.
The primary service for making HTTP requests with full Observable support and type safety.
/**
* Performs HTTP requests and returns observables of the response
* Supports all HTTP methods with full type safety and configuration options
*/
export class HttpClient {
/** Make a generic HTTP request with full control over the request */
request<R>(req: HttpRequest<any>): Observable<HttpEvent<R>>;
request<R>(method: string, url: string, options?: HttpRequestOptions & { observe?: 'body'; responseType?: 'json' }): Observable<R>;
request<R>(method: string, url: string, options: HttpRequestOptions & { observe: 'events'; responseType?: 'json' }): Observable<HttpEvent<R>>;
request<R>(method: string, url: string, options: HttpRequestOptions & { observe: 'response'; responseType?: 'json' }): Observable<HttpResponse<R>>;
request(method: string, url: string, options: HttpRequestOptions & { observe: 'events'; responseType: 'text' }): Observable<HttpEvent<string>>;
request(method: string, url: string, options: HttpRequestOptions & { observe: 'response'; responseType: 'text' }): Observable<HttpResponse<string>>;
request(method: string, url: string, options?: HttpRequestOptions & { responseType: 'text' }): Observable<string>;
/** Perform GET request */
get<T>(url: string, options?: HttpRequestOptions & { observe?: 'body'; responseType?: 'json' }): Observable<T>;
get(url: string, options: HttpRequestOptions & { observe: 'events'; responseType?: 'json' }): Observable<HttpEvent<Object>>;
get(url: string, options: HttpRequestOptions & { observe: 'response'; responseType?: 'json' }): Observable<HttpResponse<Object>>;
get(url: string, options: HttpRequestOptions & { observe: 'events'; responseType: 'text' }): Observable<HttpEvent<string>>;
get(url: string, options: HttpRequestOptions & { observe: 'response'; responseType: 'text' }): Observable<HttpResponse<string>>;
get(url: string, options?: HttpRequestOptions & { responseType: 'text' }): Observable<string>;
get(url: string, options: HttpRequestOptions & { responseType: 'blob' }): Observable<Blob>;
get(url: string, options: HttpRequestOptions & { responseType: 'arraybuffer' }): Observable<ArrayBuffer>;
/** Perform POST request */
post<T>(url: string, body: any | null, options?: HttpRequestOptions & { observe?: 'body'; responseType?: 'json' }): Observable<T>;
post(url: string, body: any | null, options: HttpRequestOptions & { observe: 'events'; responseType?: 'json' }): Observable<HttpEvent<Object>>;
post(url: string, body: any | null, options: HttpRequestOptions & { observe: 'response'; responseType?: 'json' }): Observable<HttpResponse<Object>>;
/** Perform PUT request */
put<T>(url: string, body: any | null, options?: HttpRequestOptions & { observe?: 'body'; responseType?: 'json' }): Observable<T>;
/** Perform PATCH request */
patch<T>(url: string, body: any | null, options?: HttpRequestOptions & { observe?: 'body'; responseType?: 'json' }): Observable<T>;
/** Perform DELETE request */
delete<T>(url: string, options?: HttpRequestOptions & { observe?: 'body'; responseType?: 'json' }): Observable<T>;
/** Perform HEAD request */
head<T>(url: string, options?: HttpRequestOptions & { observe?: 'body'; responseType?: 'json' }): Observable<T>;
/** Perform OPTIONS request */
options<T>(url: string, options?: HttpRequestOptions & { observe?: 'body'; responseType?: 'json' }): Observable<T>;
/** Perform JSONP request */
jsonp<T>(url: string, callbackParam: string): Observable<T>;
}
/** Options for HTTP requests */
interface HttpRequestOptions {
headers?: HttpHeaders | { [header: string]: string | string[] };
context?: HttpContext;
observe?: 'body' | 'events' | 'response';
params?: HttpParams | { [param: string]: string | number | boolean | ReadonlyArray<string | number | boolean> };
reportProgress?: boolean;
responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
withCredentials?: boolean;
}Usage Examples:
@Injectable()
export class ApiService {
constructor(private http: HttpClient) {}
// Basic GET request
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users');
}
// GET with parameters
getUserById(id: number): Observable<User> {
return this.http.get<User>(`/api/users/${id}`);
}
// GET with query parameters
getFilteredUsers(filters: UserFilters): Observable<User[]> {
const params = new HttpParams()
.set('role', filters.role)
.set('active', filters.active.toString())
.set('page', filters.page.toString());
return this.http.get<User[]>('/api/users', { params });
}
// POST request
createUser(user: CreateUserRequest): Observable<User> {
return this.http.post<User>('/api/users', user);
}
// PUT request
updateUser(id: number, user: UpdateUserRequest): Observable<User> {
return this.http.put<User>(`/api/users/${id}`, user);
}
// DELETE request
deleteUser(id: number): Observable<void> {
return this.http.delete<void>(`/api/users/${id}`);
}
// Request with custom headers
getProtectedData(): Observable<any> {
const headers = new HttpHeaders({
'Authorization': 'Bearer ' + this.authService.getToken(),
'Content-Type': 'application/json'
});
return this.http.get('/api/protected', { headers });
}
// Full response with status
getUserWithStatus(id: number): Observable<HttpResponse<User>> {
return this.http.get<User>(`/api/users/${id}`, { observe: 'response' });
}
// Progress tracking for file upload
uploadFile(file: File): Observable<HttpEvent<any>> {
const formData = new FormData();
formData.append('file', file);
return this.http.post('/api/upload', formData, {
reportProgress: true,
observe: 'events'
});
}
// Different response types
downloadFile(): Observable<Blob> {
return this.http.get('/api/files/download', { responseType: 'blob' });
}
getTextData(): Observable<string> {
return this.http.get('/api/text', { responseType: 'text' });
}
}Immutable representation of an HTTP request.
/**
* Immutable object representing an HTTP request
* Contains all information needed to make the request
*/
export class HttpRequest<T> {
/** Request body */
readonly body: T | null;
/** Request headers */
readonly headers: HttpHeaders;
/** Request context for interceptors */
readonly context: HttpContext;
/** Whether to report upload/download progress */
readonly reportProgress: boolean;
/** Whether to send credentials */
readonly withCredentials: boolean;
/** Expected response type */
readonly responseType: 'arraybuffer' | 'blob' | 'json' | 'text';
/** HTTP method */
readonly method: string;
/** Query parameters */
readonly params: HttpParams;
/** Complete URL with parameters */
readonly urlWithParams: string;
constructor(method: string, url: string, third?: T | HttpRequestInit, fourth?: HttpRequestInit);
/** Serialize the request body for transmission */
serializeBody(): ArrayBuffer | Blob | FormData | URLSearchParams | string | null;
/** Detect content type header for the request */
detectContentTypeHeader(): string | null;
/** Create a clone of this request with optional modifications */
clone(): HttpRequest<T>;
clone(update: HttpRequestInit & { body?: any }): HttpRequest<any>;
clone<V>(update: HttpRequestInit & { body?: V }): HttpRequest<V>;
}
/** Configuration for HttpRequest constructor */
interface HttpRequestInit {
headers?: HttpHeaders;
context?: HttpContext;
reportProgress?: boolean;
params?: HttpParams;
responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
withCredentials?: boolean;
}Represents a successful HTTP response with full metadata.
/**
* Full HTTP response with body, headers, and status information
* Extends HttpResponseBase with the response body
*/
export class HttpResponse<T> extends HttpResponseBase {
/** Response body */
readonly body: T | null;
/** Response type indicator */
readonly type: HttpEventType.Response;
constructor(init?: HttpResponseInit<T>);
/** Create a clone of this response with optional modifications */
clone(): HttpResponse<T>;
clone(update: HttpResponseInit<T>): HttpResponse<T>;
clone<V>(update: HttpResponseInit<V>): HttpResponse<V>;
}
/** Base class for HTTP responses */
export abstract class HttpResponseBase {
/** Response headers */
readonly headers: HttpHeaders;
/** HTTP status code */
readonly status: number;
/** HTTP status text */
readonly statusText: string;
/** Request URL */
readonly url: string | null;
/** Whether response indicates success (200-299 status) */
readonly ok: boolean;
/** Response type */
readonly type: HttpEventType.Response | HttpEventType.ResponseHeader;
}
/** HTTP response containing only headers (for HEAD requests) */
export class HttpHeaderResponse extends HttpResponseBase {
readonly type: HttpEventType.ResponseHeader;
clone(update?: { headers?: HttpHeaders; status?: number; statusText?: string; url?: string }): HttpHeaderResponse;
}
/** HTTP error response */
export class HttpErrorResponse extends HttpResponseBase implements Error {
readonly name: string;
readonly message: string;
readonly error: any | null;
readonly ok: boolean; // Always false
constructor(init: HttpErrorResponseInit);
}Usage Examples:
@Component({
template: `
<div *ngIf="loading">Loading...</div>
<div *ngIf="user">
<h2>{{ user.name }}</h2>
<p>Status: {{ responseStatus }}</p>
<p>Response time: {{ responseTime }}ms</p>
</div>
<div *ngIf="error">Error: {{ error.message }}</div>
`
})
export class UserDetailComponent {
user: User | null = null;
loading = false;
error: HttpErrorResponse | null = null;
responseStatus: number = 0;
responseTime: number = 0;
constructor(private userService: UserService) {}
loadUser(id: number) {
this.loading = true;
this.error = null;
const startTime = Date.now();
// Get full response with metadata
this.userService.getUserWithResponse(id).subscribe({
next: (response: HttpResponse<User>) => {
this.user = response.body;
this.responseStatus = response.status;
this.responseTime = Date.now() - startTime;
this.loading = false;
// Access response headers
const contentType = response.headers.get('content-type');
const customHeader = response.headers.get('x-custom-header');
console.log('Response headers:', {
contentType,
customHeader,
etag: response.headers.get('etag')
});
},
error: (error: HttpErrorResponse) => {
this.error = error;
this.loading = false;
console.error('HTTP Error:', {
status: error.status,
statusText: error.statusText,
message: error.message,
error: error.error
});
}
});
}
}
@Injectable()
export class UserService {
constructor(private http: HttpClient) {}
getUserWithResponse(id: number): Observable<HttpResponse<User>> {
return this.http.get<User>(`/api/users/${id}`, { observe: 'response' });
}
createUserRequest(userData: any): HttpRequest<any> {
return new HttpRequest('POST', '/api/users', userData, {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'X-Requested-With': 'Angular'
}),
reportProgress: true
});
}
}Immutable container for HTTP headers with fluent API.
/**
* Immutable set of HTTP headers with fluent API for manipulation
* Supports case-insensitive header names and multiple values per header
*/
export class HttpHeaders {
constructor(headers?: string | { [name: string]: string | string[] });
/** Check if header exists */
has(name: string): boolean;
/** Get first value of header */
get(name: string): string | null;
/** Get all header names */
keys(): string[];
/** Get all values for header */
getAll(name: string): string[] | null;
/** Add header value (keeps existing values) */
append(name: string, value: string | string[]): HttpHeaders;
/** Set header value (replaces existing values) */
set(name: string, value: string | string[]): HttpHeaders;
/** Remove header or specific value */
delete(name: string, value?: string | string[]): HttpHeaders;
/** Serialize headers for network transmission */
forEach(fn: (name: string, values: string[]) => void): void;
}Immutable container for URL parameters with fluent API.
/**
* Immutable set of URL parameters with fluent API for manipulation
* Handles URL encoding and multiple values per parameter
*/
export class HttpParams {
constructor(options?: HttpParamsOptions);
/** Check if parameter exists */
has(param: string): boolean;
/** Get first value of parameter */
get(param: string): string | null;
/** Get all values for parameter */
getAll(param: string): string[] | null;
/** Get all parameter names */
keys(): string[];
/** Add parameter value (keeps existing values) */
append(param: string, value: string | number | boolean): HttpParams;
/** Add multiple parameters from object */
appendAll(params: { [param: string]: string | number | boolean | ReadonlyArray<string | number | boolean> }): HttpParams;
/** Set parameter value (replaces existing values) */
set(param: string, value: string | number | boolean): HttpParams;
/** Remove parameter or specific value */
delete(param: string, value?: string | number | boolean): HttpParams;
/** Serialize parameters to query string */
toString(): string;
}
/** Options for HttpParams constructor */
interface HttpParamsOptions {
fromString?: string;
fromObject?: { [param: string]: string | number | boolean | ReadonlyArray<string | number | boolean> };
encoder?: HttpParameterCodec;
}
/** Interface for custom parameter encoding */
interface HttpParameterCodec {
encodeKey(key: string): string;
encodeValue(value: string): string;
decodeKey(key: string): string;
decodeValue(value: string): string;
}
/** Default URL encoding implementation */
export class HttpUrlEncodingCodec implements HttpParameterCodec {
encodeKey(key: string): string;
encodeValue(value: string): string;
decodeKey(key: string): string;
decodeValue(value: string): string;
}Usage Examples:
@Injectable()
export class ApiService {
constructor(private http: HttpClient) {}
// Working with headers
createAuthenticatedRequest<T>(url: string): Observable<T> {
const headers = new HttpHeaders()
.set('Authorization', `Bearer ${this.getToken()}`)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.append('X-Custom-Header', 'value1')
.append('X-Custom-Header', 'value2'); // Multiple values
return this.http.get<T>(url, { headers });
}
// Working with parameters
searchUsers(criteria: SearchCriteria): Observable<User[]> {
let params = new HttpParams()
.set('query', criteria.query)
.set('page', criteria.page.toString())
.set('limit', criteria.limit.toString());
// Conditional parameters
if (criteria.role) {
params = params.set('role', criteria.role);
}
if (criteria.tags && criteria.tags.length > 0) {
// Multiple values for same parameter
criteria.tags.forEach(tag => {
params = params.append('tags', tag);
});
}
return this.http.get<User[]>('/api/users/search', { params });
}
// Parameters from object
getFilteredData(filters: any): Observable<any[]> {
const params = new HttpParams({ fromObject: filters });
return this.http.get<any[]>('/api/data', { params });
}
// Parameters from query string
parseUrlParams(queryString: string): HttpParams {
return new HttpParams({ fromString: queryString });
}
// Custom encoding
getWithCustomEncoding(): Observable<any> {
const customEncoder: HttpParameterCodec = {
encodeKey: (key: string) => encodeURIComponent(key),
encodeValue: (value: string) => encodeURIComponent(value),
decodeKey: (key: string) => decodeURIComponent(key),
decodeValue: (value: string) => decodeURIComponent(value)
};
const params = new HttpParams({
fromObject: { 'special chars': 'hello world!' },
encoder: customEncoder
});
return this.http.get('/api/encoded', { params });
}
private getToken(): string {
return localStorage.getItem('auth_token') || '';
}
}
@Component({})
export class HeaderInspectorComponent {
checkHeaders() {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'X-Multi-Value': ['value1', 'value2']
});
console.log('Has Content-Type:', headers.has('content-type')); // true (case insensitive)
console.log('Content-Type:', headers.get('Content-Type'));
console.log('All X-Multi-Value:', headers.getAll('X-Multi-Value'));
console.log('All header names:', headers.keys());
// Iterate over all headers
headers.forEach((name, values) => {
console.log(`${name}: ${values.join(', ')}`);
});
}
}Type-safe context for passing data through HTTP interceptors.
/**
* Type-safe context store for HTTP requests
* Allows passing data through interceptor chain
*/
export class HttpContext {
/** Set context value for token */
set<T>(token: HttpContextToken<T>, value: T): HttpContext;
/** Get context value for token */
get<T>(token: HttpContextToken<T>): T;
/** Delete context value for token */
delete<T>(token: HttpContextToken<T>): HttpContext;
/** Check if context has value for token */
has<T>(token: HttpContextToken<T>): boolean;
/** Get all context token keys */
keys(): IterableIterator<HttpContextToken<unknown>>;
}
/**
* Token for type-safe context values
* Acts as both key and type information
*/
export class HttpContextToken<T> {
constructor(public readonly defaultValue: () => T);
}Intercept and modify HTTP requests and responses.
/**
* Interface for HTTP interceptors (class-based)
*/
export interface HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>;
}
/**
* Function-based HTTP interceptor
*/
export type HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => Observable<HttpEvent<unknown>>;
/**
* Function signature for next handler in interceptor chain
*/
export type HttpHandlerFn = (req: HttpRequest<unknown>) => Observable<HttpEvent<unknown>>;
/**
* Abstract base class for HTTP handlers
*/
export abstract class HttpHandler {
abstract handle(req: HttpRequest<any>): Observable<HttpEvent<any>>;
}
/**
* HTTP backend interface
*/
export abstract class HttpBackend implements HttpHandler {
abstract handle(req: HttpRequest<any>): Observable<HttpEvent<any>>;
}
/** Injection token for HTTP interceptors */
export const HTTP_INTERCEPTORS: InjectionToken<HttpInterceptor[]>;Usage Examples:
// Context usage
const IS_CACHE_ENABLED = new HttpContextToken<boolean>(() => true);
const RETRY_COUNT = new HttpContextToken<number>(() => 3);
@Injectable()
export class ApiService {
constructor(private http: HttpClient) {}
getCachedData(): Observable<any> {
const context = new HttpContext()
.set(IS_CACHE_ENABLED, true)
.set(RETRY_COUNT, 5);
return this.http.get('/api/data', { context });
}
getNonCachedData(): Observable<any> {
const context = new HttpContext().set(IS_CACHE_ENABLED, false);
return this.http.get('/api/fresh-data', { context });
}
}
// Function-based interceptor
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const authService = inject(AuthService);
const token = authService.getToken();
if (token) {
const authReq = req.clone({
headers: req.headers.set('Authorization', `Bearer ${token}`)
});
return next(authReq);
}
return next(req);
};
// Class-based interceptor
@Injectable()
export class LoggingInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const startTime = Date.now();
console.log(`[HTTP] ${req.method} ${req.url}`);
return next.handle(req).pipe(
tap(event => {
if (event.type === HttpEventType.Response) {
const duration = Date.now() - startTime;
console.log(`[HTTP] ${req.method} ${req.url} - ${event.status} (${duration}ms)`);
}
}),
catchError(error => {
const duration = Date.now() - startTime;
console.error(`[HTTP] ${req.method} ${req.url} - ERROR (${duration}ms)`, error);
return throwError(() => error);
})
);
}
}
// Caching interceptor using context
@Injectable()
export class CacheInterceptor implements HttpInterceptor {
private cache = new Map<string, HttpResponse<any>>();
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Check if caching is enabled for this request
if (!req.context.get(IS_CACHE_ENABLED) || req.method !== 'GET') {
return next.handle(req);
}
const cacheKey = req.urlWithParams;
const cached = this.cache.get(cacheKey);
if (cached) {
console.log('Cache hit:', cacheKey);
return of(cached);
}
return next.handle(req).pipe(
filter(event => event.type === HttpEventType.Response),
tap(event => {
if (event instanceof HttpResponse) {
this.cache.set(cacheKey, event);
console.log('Cached response:', cacheKey);
}
})
);
}
}
// Provider configuration
@NgModule({
providers: [
// Function-based interceptors
provideHttpClient(
withInterceptors([authInterceptor, loggingInterceptor])
),
// Or class-based interceptors
{
provide: HTTP_INTERCEPTORS,
useClass: LoggingInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: CacheInterceptor,
multi: true
}
]
})
export class AppModule {}Events emitted during HTTP request lifecycle.
/** Types of HTTP events */
export enum HttpEventType {
Sent = 0,
UploadProgress = 1,
ResponseHeader = 2,
DownloadProgress = 3,
Response = 4,
User = 5
}
/** Union type for all HTTP events */
export type HttpEvent<T> =
| HttpSentEvent
| HttpHeaderResponse
| HttpResponse<T>
| HttpProgressEvent
| HttpUserEvent<T>;
/** Event indicating request was sent */
export interface HttpSentEvent {
type: HttpEventType.Sent;
}
/** Base interface for progress events */
export interface HttpProgressEvent {
type: HttpEventType.DownloadProgress | HttpEventType.UploadProgress;
loaded: number;
total?: number;
}
/** Download progress event */
export interface HttpDownloadProgressEvent extends HttpProgressEvent {
type: HttpEventType.DownloadProgress;
partialText?: string;
}
/** Upload progress event */
export interface HttpUploadProgressEvent extends HttpProgressEvent {
type: HttpEventType.UploadProgress;
}
/** Custom user event */
export interface HttpUserEvent<T> {
type: HttpEventType.User;
}Comprehensive enumeration of HTTP status codes.
/** Standard HTTP status codes */
export enum HttpStatusCode {
Continue = 100,
SwitchingProtocols = 101,
Processing = 102,
EarlyHints = 103,
Ok = 200,
Created = 201,
Accepted = 202,
NonAuthoritativeInformation = 203,
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
MultiStatus = 207,
AlreadyReported = 208,
ImUsed = 226,
MultipleChoices = 300,
MovedPermanently = 301,
Found = 302,
SeeOther = 303,
NotModified = 304,
UseProxy = 305,
Unused = 306,
TemporaryRedirect = 307,
PermanentRedirect = 308,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
ProxyAuthenticationRequired = 407,
RequestTimeout = 408,
Conflict = 409,
Gone = 410,
LengthRequired = 411,
PreconditionFailed = 412,
PayloadTooLarge = 413,
UriTooLong = 414,
UnsupportedMediaType = 415,
RangeNotSatisfiable = 416,
ExpectationFailed = 417,
ImATeapot = 418,
MisdirectedRequest = 421,
UnprocessableEntity = 422,
Locked = 423,
FailedDependency = 424,
TooEarly = 425,
UpgradeRequired = 426,
PreconditionRequired = 428,
TooManyRequests = 429,
RequestHeaderFieldsTooLarge = 431,
UnavailableForLegalReasons = 451,
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
HttpVersionNotSupported = 505,
VariantAlsoNegotiates = 506,
InsufficientStorage = 507,
LoopDetected = 508,
NotExtended = 510,
NetworkAuthenticationRequired = 511
}Configuration modules and providers for HTTP client.
/** Main HTTP client module */
export class HttpClientModule {
static forRoot(): ModuleWithProviders<HttpClientModule>;
}
/** JSONP support module */
export class HttpClientJsonpModule {}
/** XSRF protection module */
export class HttpClientXsrfModule {
static withOptions(options: HttpClientXsrfOptions): ModuleWithProviders<HttpClientXsrfModule>;
}
/** Provider function for HTTP client with features */
export function provideHttpClient(...features: HttpFeature<HttpFeatureKind>[]): EnvironmentProviders;
/** HTTP feature types */
export enum HttpFeatureKind {
Interceptors,
LegacyInterceptors,
CustomXsrfConfiguration,
NoXsrfProtection,
JsonpSupport,
RequestsMadeViaParent,
Fetch
}
/** Feature configuration functions */
export function withInterceptors(interceptorFns: HttpInterceptorFn[]): HttpFeature<HttpFeatureKind.Interceptors>;
export function withInterceptorsFromDi(): HttpFeature<HttpFeatureKind.LegacyInterceptors>;
export function withXsrfConfiguration(options: HttpClientXsrfOptions): HttpFeature<HttpFeatureKind.CustomXsrfConfiguration>;
export function withNoXsrfProtection(): HttpFeature<HttpFeatureKind.NoXsrfProtection>;
export function withJsonpSupport(): HttpFeature<HttpFeatureKind.JsonpSupport>;
export function withRequestsMadeViaParent(): HttpFeature<HttpFeatureKind.RequestsMadeViaParent>;
export function withFetch(): HttpFeature<HttpFeatureKind.Fetch>;Usage Examples:
// Progress tracking
@Component({
template: `
<div *ngIf="uploadProgress !== null">
<div class="progress-bar">
<div [style.width.%]="uploadProgress"></div>
</div>
<p>{{ uploadProgress }}% uploaded</p>
</div>
`
})
export class FileUploadComponent {
uploadProgress: number | null = null;
constructor(private http: HttpClient) {}
uploadFile(file: File) {
const formData = new FormData();
formData.append('file', file);
this.http.post('/api/upload', formData, {
reportProgress: true,
observe: 'events'
}).subscribe(event => {
switch (event.type) {
case HttpEventType.Sent:
console.log('Request sent');
break;
case HttpEventType.UploadProgress:
if (event.total) {
this.uploadProgress = Math.round(100 * event.loaded / event.total);
}
break;
case HttpEventType.Response:
console.log('Upload complete', event.body);
this.uploadProgress = null;
break;
}
});
}
}
// Status code handling
@Injectable()
export class ErrorHandlingService {
handleHttpError(error: HttpErrorResponse): string {
switch (error.status) {
case HttpStatusCode.BadRequest:
return 'Invalid request data';
case HttpStatusCode.Unauthorized:
return 'Please log in';
case HttpStatusCode.Forbidden:
return 'Access denied';
case HttpStatusCode.NotFound:
return 'Resource not found';
case HttpStatusCode.InternalServerError:
return 'Server error occurred';
default:
return `HTTP Error ${error.status}: ${error.statusText}`;
}
}
}
// Modern provider configuration
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(
withInterceptors([authInterceptor, loggingInterceptor]),
withFetch(), // Use Fetch API instead of XMLHttpRequest
withJsonpSupport(), // Enable JSONP
withXsrfConfiguration({
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN'
})
),
// Other providers...
]
});