HTTP
Angular HttpClient — REST API bilan ishlash uchun RxJS Observable qaytaradigan HTTP client. Interceptor'lar esa har bir so'rov/javobni markaziy tarzda o'zgartirish imkonini beradi.
HttpClient — get, post, put, patch, delete
Nima bu?
HttpClient — @angular/common/http modulidan keladigan service. Barcha HTTP metodlari Observable qaytaradi (Promise emas). subscribe yoki async pipe orqali natija olinadi. Standalone ilovada provideHttpClient() bilan ro'yxatdan o'tkaziladi.
Kod misoli
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http';
bootstrapApplication(AppComponent, {
providers: [provideHttpClient()],
});
interface Product {
id: number;
name: string;
price: number;
}
@Injectable({ providedIn: 'root' })
export class ProductApiService {
private http = inject(HttpClient);
private baseUrl = '/api/products';
getAll(): Observable<Product[]> {
return this.http.get<Product[]>(this.baseUrl);
}
getById(id: number): Observable<Product> {
return this.http.get<Product>(`${this.baseUrl}/${id}`);
}
create(product: Omit<Product, 'id'>): Observable<Product> {
return this.http.post<Product>(this.baseUrl, product);
}
update(id: number, product: Partial<Product>): Observable<Product> {
return this.http.put<Product>(`${this.baseUrl}/${id}`, product);
}
patchPrice(id: number, price: number): Observable<Product> {
return this.http.patch<Product>(`${this.baseUrl}/${id}`, { price });
}
delete(id: number): Observable<void> {
return this.http.delete<void>(`${this.baseUrl}/${id}`);
}
}
Imtihonda
Savol: HttpClient nima qaytaradi — Promise yoki Observable?
Javob: Observable. Bu cancel qilish, retry, operatorlar zanjiri va bir nechta subscriber uchun qulay.
Yodlash uchun
HTTP options — params, headers, responseType
Nima bu?
Har bir HTTP so'rov uchun HttpParams, HttpHeaders va responseType orqali qo'shimcha sozlash mumkin. Query parametrlar, auth header, blob/arraybuffer javob turlari shu yerda beriladi.
Kod misoli
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class SearchService {
private http = inject(HttpClient);
searchProducts(query: string, page = 1, limit = 10): Observable<Product[]> {
const params = new HttpParams()
.set('q', query)
.set('page', page.toString())
.set('limit', limit.toString());
const headers = new HttpHeaders({
'X-Request-Id': crypto.randomUUID(),
});
return this.http.get<Product[]>('/api/products', { params, headers });
}
downloadPdf(id: number): Observable<Blob> {
return this.http.get(`/api/reports/${id}`, {
responseType: 'blob',
});
}
getRawText(): Observable<string> {
return this.http.get('/api/readme', { responseType: 'text' });
}
}
Imtihonda
Savol: HttpParams immutable — yangi param qo'shish qanday?
Javob: .set() va .append() yangi HttpParams instance qaytaradi. Eski ob'ekt o'zgarmaydi — zanjirlab yozish kerak.
Yodlash uchun
HTTP Interceptor — request/response transform
Nima bu?
Interceptor — HTTP so'rov ketishidan oldin yoki javob kelganda aralashuvchi. Auth token qo'shish, loading spinner, logging — bularning hammasi markaziy joyda bajariladi. Class-based interceptor HttpInterceptor interfeysini implement qiladi.
Kod misoli
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
private loading = inject(LoadingService);
intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
this.loading.show();
return next.handle(req).pipe(finalize(() => this.loading.hide()));
}
}
// main.ts (class interceptor)
providers: [
provideHttpClient(withInterceptorsFromDi()),
{ provide: HTTP_INTERCEPTORS, useClass: LoadingInterceptor, multi: true },
]
Imtihonda
Savol: Interceptor zanjiri qanday ishlaydi?
Javob: So'rov birinchi ro'yxatdagi interceptordan o'tadi, next.handle(req) keyingisiga uzatadi. Javob esa teskari tartibda qaytadi — oxirgi interceptor birinchi javobni ko'radi.
Yodlash uchun
Functional interceptor (v15+)
Nima bu?
Angular 15+ da HttpInterceptorFn — oddiy funksiya ko'rinishidagi interceptor. Class o'rniga inject() ishlatiladi. provideHttpClient(withInterceptors([...])) bilan ro'yxatdan o'tkaziladi. Zamonaviy standalone ilovalar uchun tavsiya etiladi.
Kod misoli
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const auth = inject(AuthService);
const token = auth.getToken();
if (!token) {
return next(req);
}
return next(
req.clone({
setHeaders: { Authorization: `Bearer ${token}` },
})
);
};
export const apiBaseInterceptor: HttpInterceptorFn = (req, next) => {
if (req.url.startsWith('/api/')) {
return next(req.clone({ url: `https://api.example.com${req.url}` }));
}
return next(req);
};
// main.ts
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(withInterceptors([apiBaseInterceptor, authInterceptor])),
],
});
Imtihonda
Savol: Functional va class interceptor bir vaqtda ishlatilsa tartib qanday?
Javob: withInterceptors ro'yxati birinchi, keyin withInterceptorsFromDi() (class-based). Functional interceptor'lar DI'siz yengilroq va tree-shake qilinadi.
Yodlash uchun
Error handling interceptor — global
Nima bu?
Global error interceptor barcha HTTP xatolarini bir joyda ushlaydi: 401 — login'ga yo'naltirish, 500 — toast xabar, network error — qayta urinish taklifi. catchError operatori bilan HttpErrorResponse tahlil qilinadi.
Kod misoli
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { catchError, throwError } from 'rxjs';
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
const router = inject(Router);
const toast = inject(ToastService);
return next(req).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 401) {
router.navigate(['/login']);
return throwError(() => error);
}
if (error.status === 0) {
toast.error('Internet aloqasi yo\'q');
} else if (error.status >= 500) {
toast.error('Server xatosi. Keyinroq urinib ko\'ring.');
} else {
toast.error(error.error?.message ?? 'Noma\'lum xato');
}
return throwError(() => error);
})
);
};
Imtihonda
Savol: Interceptor'da xatoni "yutib" yuborish to'g'rimi?
Javob: Yo'q, agar component ham xatoni bilishi kerak bo'lsa. catchError ichida UI ko'rsatgandan keyin throwError(() => error) bilan qayta tashlash kerak — aks holda subscriber xato olmaydi.
Yodlash uchun
Retry va exponential backoff
Nima bu?
Tarmoq yoki server vaqtincha ishlamaganda so'rovni qayta yuborish. retry(n) — oddiy qayta urinish. Exponential backoff — har urinish orasidagi kutish vaqti ikki barobar oshadi (1s, 2s, 4s...) — serverga bosim kamayadi.
Kod misoli
import { HttpClient } from '@angular/common/http';
import { retry, timer } from 'rxjs';
import { retryWhen, mergeMap, finalize } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class ResilientApiService {
private http = inject(HttpClient);
// Oddiy retry — 3 marta, darhol
getWithRetry<T>(url: string): Observable<T> {
return this.http.get<T>(url).pipe(retry(3));
}
// Exponential backoff — RxJS 7+ retry with delay config
getWithBackoff<T>(url: string): Observable<T> {
return this.http.get<T>(url).pipe(
retry({
count: 3,
delay: (error, retryCount) => {
if (error.status === 429 || error.status >= 500) {
return timer(Math.pow(2, retryCount) * 1000); // 2s, 4s, 8s
}
throw error; // 4xx — qayta urinma
},
})
);
}
}
// Interceptor darajasida
export const retryInterceptor: HttpInterceptorFn = (req, next) => {
if (req.method !== 'GET') {
return next(req); // faqat GET uchun retry
}
return next(req).pipe(retry({ count: 2, delay: 1000 }));
};
Imtihonda
Savol: POST so'rovni avtomatik retry qilish xavflimi?
Javob: Ha. POST ikki marta bajarilsa duplicate ma'lumot yaratilishi mumkin (to'lov, buyurtma). Retry faqat idempotent so'rovlar uchun: GET, HEAD, ba'zi PUT.
Yodlash uchun
