Angular Resource API i httpResource: Kompletny przewodnik (Stabilne w Angular 22)
Resource API i httpResource w Angular sa teraz stabilne od Angular 22. Przewodnik obejmuje resource(), rxResource(), httpResource(), nowy helper chain() do zaleznych zasobow, walidacje Zod i pytania rekrutacyjne.

Angular Resource API oraz httpResource umozliwiaja reaktywne pobieranie danych oparte na sygnalach, ktore automatycznie sledzi stany ladowania, bledu i gotowosci. Wprowadzone w Angular 20, te API uzyskaly status stabilny w Angular 22, zastepujac rozbudowane wzorce subskrypcji HttpClient reaktywnymi prymitywami.
Resource API (resource(), rxResource(), httpResource()) przeszlo ze statusu eksperymentalnego do stabilnego w Angular 22 (czerwiec 2026). Nazewnictwo params i stream, literaly lancuchowe dla statusow oraz nowy helper chain() do zaleznych zasobow sa gotowe do produkcji. Przy aktualizacji z Angular 20 lub 21 powierzchnia API pozostaje kompatybilna.
Trzy warianty Resource
Angular oferuje trzy sposoby ladowania asynchronicznych danych jako sygnalow. Kazdy obsluguje inny przypadek uzycia, ale wszystkie dziela ten sam reaktywny model: deklaracja zaleznosci, definicja loadera i konsumpcja wyniku przez sygnaly.
resource()operuje na Promise. Idealny przy uzyciufetch()lub dowolnego API opartego na Promise.rxResource()operuje na Observable. Wlasciwy wybor, gdy potrzebne sa operatory RxJS takie jakdebounceTime,retryczyswitchMap.httpResource()opakowuje bezposrednio AngularHttpClient. Interceptory, narzedzia testowe i walidacja schematu dzialaja bez dodatkowej konfiguracji.
Kluczowa roznica miedzy httpResource a pozostalymi dwoma: httpResource uzywa wewnetrznie HttpClient, co oznacza, ze istniejace interceptory dzialaja bez zmian. Oryginalne API resource() omijalo calkowicie HttpClient, co stanowilo ograniczenie w Angular 19.
Budowanie profilu uzytkownika za pomoca resource()
Funkcja resource() przyjmuje obliczenie params oraz funkcje loader. Gdy sygnaly wewnatrz params ulegna zmianie, loader jest automatycznie wykonywany ponownie.
import { Component, signal, resource } from '@angular/core';
interface User {
id: number;
name: string;
email: string;
}
@Component({
selector: 'app-user-profile',
template: \`
@if (userResource.hasValue()) {
<h2>{{ userResource.value().name }}</h2>
<p>{{ userResource.value().email }}</p>
} @else if (userResource.isLoading()) {
<p>Loading profile...</p>
} @else if (userResource.error()) {
<p>Failed to load user</p>
}
\`,
})
export class UserProfileComponent {
userId = signal(1);
// params produces the reactive dependency
// loader receives it and returns a Promise
userResource = resource<User, number>({
params: () => this.userId(),
loader: async ({ params: id, abortSignal }) => {
const res = await fetch(\`/api/users/${id}\`, { signal: abortSignal });
return res.json();
},
});
loadUser(id: number) {
this.userId.set(id); // triggers automatic refetch
}
}Parametr abortSignal pozwala Angular anulowac trwajace zadania, gdy userId zmieni sie przed zakonczeniem poprzedniego zadania. Zapobiega to wyscigom bez recznego zarzadzania subskrypcjami.
Reaktywne pobieranie danych z httpResource
httpResource eliminuje kod szablonowy, laczac deklaracje URL i wykonanie HTTP w jednym wywolaniu. Zwraca HttpResourceRef, ktory eksponuje value, isLoading, error, status i headers jako sygnaly.
import { Component, signal, computed } from '@angular/core';
import { httpResource } from '@angular/common/http';
interface Product {
id: number;
name: string;
price: number;
category: string;
}
@Component({
selector: 'app-product-list',
template: \`
@if (products.hasValue()) {
@for (product of products.value(); track product.id) {
<div class="product-card">
<h3>{{ product.name }}</h3>
<span>{{ product.price | currency }}</span>
</div>
}
} @else if (products.isLoading()) {
<p>Loading products...</p>
}
\`,
})
export class ProductListComponent {
category = signal('electronics');
// httpResource re-fetches whenever category() changes
products = httpResource<Product[]>(() => ({
url: '/api/products',
params: { category: this.category() },
}));
filterByCategory(cat: string) {
this.category.set(cat); // pending request is cancelled, new one starts
}
}Funkcja przekazana do httpResource zwraca obiekt konfiguracji zadania. Angular sledzi odczyty sygnalow wewnatrz tej funkcji, wiec zmiana category wyzwala nowe zadanie GET. Jesli zadanie jest juz w trakcie realizacji, Angular anuluje je przed rozpoczeciem nowego.
httpResource jest zaprojektowany do pobierania danych (zadania GET). Uzywanie go do operacji POST, PUT lub DELETE jest niebezpieczne, poniewaz anulowanie zadania mogloby przerwac mutacje w trakcie realizacji. Dla operacji zapisu nalezy uzywac HttpClient bezposrednio lub opakowac mutacje w metode serwisowa.
Laczenie zasobow z chain()
Angular 22 wprowadzil helper chain() do ladowania zaleznych zasobow. Gdy jeden zasob zalezy od wartosci innego, chain() automatycznie propaguje stany ladowania i bledu.
import { Component, signal } from '@angular/core';
import { httpResource } from '@angular/common/http';
interface User {
id: number;
name: string;
authorId: string;
}
interface Post {
id: number;
title: string;
content: string;
}
@Component({
selector: 'app-user-posts',
template: \`
@if (postsResource.isLoading()) {
<p>Loading...</p>
} @else if (postsResource.hasValue()) {
<h2>Posts by {{ userResource.value().name }}</h2>
@for (post of postsResource.value(); track post.id) {
<article>
<h3>{{ post.title }}</h3>
</article>
}
} @else if (postsResource.error()) {
<p>Failed to load posts</p>
}
\`,
})
export class UserPostsComponent {
userId = signal(1);
userResource = httpResource<User>(() => \`/api/users/${this.userId()}\`);
// chain() propagates userResource's status to postsResource
postsResource = httpResource<Post[]>({
params: ({ chain }) => {
const user = chain(this.userResource);
return { url: '/api/posts', params: { authorId: user.authorId } };
},
});
}chain(userResource) nie zwraca po prostu wartosci. Podczas gdy userResource sie laduje, postsResource rowniez raportuje stan ladowania i jego loader nie jest wykonywany. Jesli userResource zwroci blad, postsResource przechodzi w stan bledu z ResourceDependencyError, ktory zawiera blad nadrzedny.
Zastepuje to wzorzec RxJS z zagniezdonymi wywolaniami switchMap jawna, domyslnie poprawna propagacja statusu.
Walidacja schematu z Zod i httpResource
Odpowiedzi API z zewnetrznych serwisow moga odbiegac od oczekiwanych struktur. Opcja parse w httpResource integruje biblioteki walidacji schematow takie jak Zod, aby wychwycic niezgodnosci w czasie wykonania zamiast cicho propagowac uszkodzone dane.
import { Component, signal } from '@angular/core';
import { httpResource } from '@angular/common/http';
import { z } from 'zod';
// Define the expected shape with Zod
const OrderSchema = z.object({
id: z.number(),
status: z.enum(['pending', 'shipped', 'delivered', 'cancelled']),
total: z.number().positive(),
items: z.array(z.object({
productId: z.number(),
quantity: z.number().int().positive(),
unitPrice: z.number().positive(),
})),
createdAt: z.string().datetime(),
});
type Order = z.infer<typeof OrderSchema>;
@Component({
selector: 'app-order',
template: \`
@if (order.hasValue()) {
<h2>Order #{{ order.value().id }}</h2>
<p>Status: {{ order.value().status }}</p>
<p>Total: {{ order.value().total | currency }}</p>
} @else if (order.error()) {
<p>Invalid order data received</p>
}
\`,
})
export class OrderComponent {
orderId = signal(42);
// parse validates the response before exposing it as a signal
order = httpResource<Order>(
() => \`/api/orders/${this.orderId()}\`,
{ parse: OrderSchema.parse }
);
}Gdy API zwraca dane niezgodne z OrderSchema, zasob przechodzi w status 'error'. Typ zwracany przez funkcje parse okresla rowniez typ TypeScript dla value(), wiec definicje schematow pelnia podwojna role jako walidatory runtime i generatory typow.
rxResource ze stream i params
Angular zmienia nazwe loader na stream oraz request na params w rxResource. Dostosowuje to nazewnictwo do semantyki streamingu, ktora obsluguje rxResource. Funkcja stream otrzymuje kontekst Observable i musi zwrocic Observable.
import { Component, signal } from '@angular/core';
import { rxResource } from '@angular/core/rxjs-interop';
import { HttpClient } from '@angular/common/http';
import { inject } from '@angular/core';
import { debounceTime, switchMap } from 'rxjs';
interface SearchResult {
id: number;
title: string;
excerpt: string;
}
@Component({
selector: 'app-search',
template: \`
<input (input)="query.set((.target).value)" placeholder="Search..." />
@if (results.isLoading()) {
<p>Searching...</p>
}
@if (results.hasValue()) {
@for (item of results.value(); track item.id) {
<div>{{ item.title }}</div>
}
}
\`,
})
export class SearchComponent {
private http = inject(HttpClient);
query = signal('');
// params (was "request") provides the reactive input
// stream (was "loader") returns an Observable
results = rxResource<SearchResult[], string>({
params: () => this.query(),
stream: ({ params: q }) =>
this.http.get<SearchResult[]>('/api/search', {
params: { q },
}),
});
}W przeciwienstwie do httpResource, rxResource daje pelna kontrole nad potokiem Observable. Operatory takie jak debounceTime czy retry moga byc laczne w lancuch wewnatrz stream. Jednak httpResource obsluguje najczestszy przypadek (pojedyncze zadanie GET) z mniejsza iloscia kodu.
Gotowy na rozmowy o Angular?
Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.
Sledzenie statusu: literaly lancuchowe zastepuja enumy
ResourceStatus jest typem unii lancuchow. Szesc mozliwych wartosci dostarcza szczegolowego wgladu w cykl zycia zasobu:
| Status | Znaczenie |
|---|---|
'idle' | params zwrocilo undefined, zadanie nie zostalo wyslane |
'loading' | Pierwsze zadanie w toku |
'reloading' | Kolejne zadanie po poprzednim sukcesie |
'resolved' | Dane dostepne w value() |
'error' | Zadanie nie powiodlo sie, error() zawiera blad |
'local' | Wartosc ustawiona lokalnie przez .set() lub .update() |
import { Component, signal, resource } from '@angular/core';
@Component({
selector: 'app-status-demo',
template: \`
<p>Status: {{ data.status() }}</p>
@switch (data.status()) {
@case ('loading') { <spinner /> }
@case ('reloading') { <subtle-spinner /> }
@case ('resolved') { <data-table [rows]="data.value()" /> }
@case ('error') { <error-banner [error]="data.error()" /> }
@case ('idle') { <p>Select a filter to load data</p> }
}
\`,
})
export class StatusDemoComponent {
filter = signal<string | undefined>(undefined);
data = resource({
params: () => this.filter(),
loader: async ({ params: f, abortSignal }) => {
const res = await fetch(\`/api/data?filter=${f}\`, { signal: abortSignal });
return res.json();
},
});
}Zwrocenie undefined z params ustawia status na 'idle' i zapobiega wykonaniu loadera. Ten wzorzec sprawdza sie przy warunkowym pobieraniu danych: wyswietla komunikat do momentu, az uzytkownik poda dane wejsciowe, a nastepnie laduje dane.
Wywolanie value() na zasobie w statusie 'error' rzuca wyjatek runtime. Nalezy zawsze zabezpieczac odczyty za pomoca hasValue() lub sprawdzac status() przed dostepem do value(). Jest to zmiana w porownaniu z Angular 19, gdzie value() zwracalo undefined w przypadku bledu.
Pytania rekrutacyjne Angular httpResource
Resource API jest standardowym tematem w pytaniach rekrutacyjnych Angular. Ponizej znajduja sie pytania, ktore sprawdzaja rzeczywiste zrozumienie wykraczajace poza powierzchowna znajomosc API.
P: Jaki problem rozwiazuje httpResource, ktorego nie rozwiazuje resource()?
resource() uzywa fetch() lub dowolnego loadera opartego na Promise, omijajac Angular HttpClient. Oznacza to, ze interceptory (dla tokenow autoryzacji, logowania, obslugi bledow) nie maja zastosowania. httpResource uzywa wewnetrznie HttpClient, wiec interceptory, narzedzia testowe (HttpTestingController) i funkcje takie jak withFetch() dzialaja bez dodatkowej konfiguracji.
P: Kiedy nalezy preferowac rxResource nad httpResource?
rxResource zapewnia pelna kontrole nad Observable poprzez funkcje stream. Nalezy go wybrac, gdy potok danych wymaga operatorow RxJS: debouncing wejscia wyszukiwania, ponawianie nieudanych zadan z wykladniczym opoznieniem lub laczenie wielu strumieni za pomoca combineLatest. Dla prostych zadan GET, httpResource wymaga mniej kodu.
P: Jak Angular obsluguje rownoczesne zadania, gdy sygnal zmienia sie szybko?
Wszystkie trzy warianty zasobow anuluja oczekujace zadania, gdy params produkuje nowa wartosc. Dla httpResource i resource(), AbortSignal anuluje bazowe fetch. Dla rxResource, Angular anuluje subskrypcje poprzedniego Observable. Zapobiega to nadpisywaniu swiezych danych przez przestarzale odpowiedzi.
P: Jaki jest cel statusu 'local'?
Wywolanie .set() lub .update() na zasobie zmienia jego wartosc lokalnie bez wyzwalania loadera. Status przechodzi na 'local', wskazujac, ze biezaca wartosc nie pochodzi z serwera. Wspiera to optymistyczne aktualizacje UI: interfejs odzwierciedla zmiane natychmiast, podczas gdy oddzielne zadanie mutacji jest w trakcie realizacji.
P: Jak dziala integracja Zod z httpResource?
Opcja parse akceptuje dowolna funkcje o sygnaturze (data: unknown) => T. Gdy nadejdzie odpowiedz HTTP, httpResource przekazuje sparsowany JSON przez parse przed ustawieniem value(). Jesli parse rzuci wyjatek (np. ZodError), zasob przechodzi w status 'error'. Typ zwracany przez parse okresla typ TypeScript dla value(), zapewniajac zarowno bezpieczenstwo runtime, jak i typy podczas kompilacji z jednej definicji schematu.
P: Jak chain() obsluguje bledy z nadrzednych zasobow?
Przy uzyciu chain(upstreamResource) w funkcji params zasobu, zalezny zasob nie wykonuje swojego loadera, jesli nadrzedny zasob laduje sie, jest w stanie idle lub bledu. Jesli nadrzedny zasob zwroci blad, zalezny zasob przechodzi w stan bledu z ResourceDependencyError. Ten blad zawiera dependency (nadrzedny zasob) i cause (rzeczywisty blad nadrzedny), co pozwala rozroznic "moje zadanie nie powiodlo sie" od "zadanie mojej zaleznosci nie powiodlo sie".
Wiecej informacji o Angular signals i ich integracji z frameworkiem znajduje sie w przewodniku po sygnalach.
Migracja z subskrypcji HttpClient na httpResource
Istniejace aplikacje Angular zazwyczaj pobieraja dane za pomoca subskrypcji HttpClient wewnatrz ngOnInit lub uzywaja AsyncPipe z Observable. Migracja do httpResource przebiega wedlug przewidywalnego wzorca:
// BEFORE: manual subscription in ngOnInit
@Component({ /* ... */ })
export class BeforeComponent implements OnInit, OnDestroy {
private http = inject(HttpClient);
private destroy$ = new Subject<void>();
users: User[] = [];
loading = false;
error: string | null = null;
ngOnInit() {
this.loading = true;
this.http.get<User[]>('/api/users')
.pipe(takeUntil(this.destroy$))
.subscribe({
next: (data) => { this.users = data; this.loading = false; },
error: (err) => { this.error = err.message; this.loading = false; },
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
// AFTER: httpResource handles lifecycle automatically
@Component({ /* ... */ })
export class AfterComponent {
users = httpResource<User[]>(() => '/api/users');
// No ngOnInit, no Subject, no manual unsubscribe
// Template uses users.value(), users.isLoading(), users.error()
}Migracja eliminuje kod szablonowy zarzadzania cyklem zycia. Czyszczenie subskrypcji nastepuje automatycznie przy zniszczeniu komponentu. Stany ladowania i bledu sa wbudowane w zasob, bez potrzeby oddzielnych flag boolowskich.
Dla aplikacji juz uzywajacych standalone components, migracja jest prosta: zastap wstrzykniecie HttpClient i logike subskrypcji pojedyncza deklaracja httpResource.
Zacznij ćwiczyć!
Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.
Zrodla
- Dokumentacja Angular Resource API - oficjalny przewodnik po resource(), rxResource() i httpResource()
- Co nowego w Angular 22.0 - omowienie Ninja Squad stabilnego Resource API i helpera chain()
- Przewodnik po interceptorach HTTP Angular - jak interceptory dzialaja z httpResource
Kluczowe wnioski dotyczace Angular Resource API
httpResourcezastepuje reczne subskrypcjeHttpClientpojedyncza reaktywna deklaracja, ktora automatycznie obsluguje ladowanie, bledy i anulowanie- Uzyj
resource()dla API opartych na Promise,rxResource()dla potokow Observable z operatorami RxJS ihttpResource()dla standardowych wywolan HTTP z obsluga interceptorow - Helper
chain()(Angular 22+) umozliwia ladowanie zaleznych zasobow z automatyczna propagacja statusu; jesli nadrzedny zasob zawiedzie, zalezny otrzymujeResourceDependencyError - Wartosci statusu to literaly lancuchowe (
'idle','loading','resolved','error','reloading','local') - Opcja
parsewhttpResourceintegruje Zod lub Valibot do walidacji schematu runtime, ktora rowniez determinuje typy TypeScript - Wywolanie
value()na zasobie w stanie bledu rzuca wyjatek; zawsze zabezpieczaj dostep za pomocahasValue()lub sprawdzajstatus()najpierw - Wszystkie warianty zasobow automatycznie anuluja trwajace zadania, gdy zaleznosci sie zmienia, zapobiegajac wyscigom bez recznej logiki anulowania
Znajdziesz błąd w Angular?
Prawdziwy fragment kodu, ukryty błąd, jedna próba dziennie. Bez konta, żeby spróbować.

Autor:
Anthony Fillion-MailletZałożyciel SharpSkill
Programista fullstack od ponad 10 lat. Prowadzi SharpSkill i odpowiada za wszystko, co się tu ukazuje.
Zaktualizowano 13 października 2026
Tagi
Udostępnij
Powiązane artykuły

NgRx Signal Store vs Klasyczny NgRx w 2026: Który Wybrać?
Kompleksowe porównanie NgRx Signal Store i klasycznego NgRx do zarządzania stanem w Angular. Praktyczne przykłady kodu z NgRx 22 i rekomendacje.

RxJS w Angularze 2026: operatory, Subjecty i interop z Signals
RxJS w Angularze 2026: opanuj operatory, Subjecty i wzorce interoperacyjności z Signals używane na produkcji oraz pytania rekrutacyjne, które padają najczęściej.

Zaawansowany Dependency Injection w Angular 2026: Providers, Tokens i Pytania Rekrutacyjne
Kompleksowy przewodnik po zaawansowanych mechanizmach Dependency Injection w Angular. Providers, InjectionToken, hierarchia injectorów oraz najczęstsze pytania na rozmowach kwalifikacyjnych.