Angular Resource API dan httpResource: Panduan Lengkap (Stabil di Angular 22)
Resource API dan httpResource Angular kini stabil sejak Angular 22. Panduan ini mencakup resource(), rxResource(), httpResource(), helper chain() untuk resource bergantung, validasi Zod, dan pertanyaan wawancara.

Angular Resource API dan httpResource menyediakan pengambilan data berbasis signal yang secara otomatis melacak status loading, error, dan resolved. Diperkenalkan di Angular 20, API ini menjadi stabil di Angular 22, menggantikan pola subscription HttpClient yang bertele-tele dengan primitif reaktif.
Resource API (resource(), rxResource(), httpResource()) naik dari eksperimental menjadi stabil di Angular 22 (Juni 2026). Penamaan params dan stream, status literal string, dan helper chain() baru untuk resource bergantung semuanya siap produksi. Jika Anda memperbarui dari Angular 20 atau 21, API tetap kompatibel.
Tiga Varian Resource
Angular menawarkan tiga cara untuk memuat data asinkron sebagai signal. Masing-masing menyasar kasus penggunaan yang berbeda, tetapi semuanya berbagi model reaktif yang sama: mendeklarasikan dependensi, mendefinisikan loader, lalu mengonsumsi hasilnya melalui signal.
resource()bekerja dengan Promise. Ideal saat menggunakanfetch()atau API berbasis promise apa pun.rxResource()bekerja dengan Observable. Pilihan tepat ketika operator RxJS sepertidebounceTime,retry, atauswitchMapdibutuhkan.httpResource()membungkusHttpClientAngular secara langsung. Interceptor, utilitas pengujian, dan validasi schema berfungsi tanpa konfigurasi tambahan.
Perbedaan utama antara httpResource dan dua varian lainnya: httpResource menggunakan HttpClient di baliknya, yang berarti interceptor yang sudah ada tetap berfungsi. API resource() versi awal sepenuhnya melewati HttpClient, yang merupakan keterbatasan di Angular 19.
Membangun Profil Pengguna dengan resource()
Fungsi resource() menerima fungsi komputasi params dan fungsi loader. Ketika signal di dalam params berubah, loader dijalankan ulang secara otomatis.
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
}
}Parameter abortSignal memungkinkan Angular membatalkan permintaan yang sedang berjalan ketika userId berubah sebelum permintaan sebelumnya selesai. Ini mencegah race condition tanpa pengelolaan subscription secara manual.
Pengambilan Data Reaktif dengan httpResource
httpResource menghilangkan boilerplate dengan menggabungkan deklarasi URL dan eksekusi HTTP dalam satu panggilan. Ia mengembalikan HttpResourceRef yang mengekspos value, isLoading, error, status, dan headers sebagai signal.
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
}
}Fungsi yang diteruskan ke httpResource mengembalikan objek konfigurasi permintaan. Angular melacak pembacaan signal di dalam fungsi tersebut, sehingga mengubah category memicu permintaan GET baru. Jika sebuah permintaan sedang berjalan, Angular membatalkannya sebelum memulai yang baru.
httpResource dirancang untuk pengambilan data (permintaan GET). Menggunakannya untuk operasi POST, PUT, atau DELETE tidak aman karena pembatalan permintaan dapat menggugurkan mutasi di tengah jalan. Untuk operasi tulis, gunakan HttpClient secara langsung atau bungkus mutasi dalam sebuah method service.
Merangkai Resource dengan chain()
Angular 22 memperkenalkan helper chain() untuk pemuatan resource yang bergantung. Ketika satu resource bergantung pada nilai resource lain, chain() meneruskan status loading dan error secara otomatis.
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) tidak hanya mengembalikan nilai. Selagi userResource sedang loading, postsResource juga melaporkan status loading dan loader-nya tidak dijalankan. Jika userResource mengalami error, postsResource beralih ke status error dengan ResourceDependencyError yang membawa error dari upstream.
Ini menggantikan pola RxJS dengan panggilan switchMap bersarang menggunakan propagasi status yang eksplisit dan benar secara default.
Validasi Schema dengan Zod dan httpResource
Respons API dari layanan eksternal bisa menyimpang dari bentuk yang diharapkan. Opsi parse pada httpResource mengintegrasikan pustaka validasi schema seperti Zod untuk menangkap ketidaksesuaian saat runtime, alih-alih meneruskan data rusak secara diam-diam.
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 }
);
}Ketika API mengembalikan data yang tidak cocok dengan OrderSchema, resource beralih ke status 'error'. Tipe kembalian fungsi parse juga menentukan tipe TypeScript dari value(), sehingga definisi schema menjalankan peran ganda sebagai validator runtime sekaligus penghasil tipe.
rxResource dengan Stream dan Params
Angular mengganti nama loader menjadi stream dan request menjadi params pada rxResource. Perubahan ini menyelaraskan penamaan dengan semantik streaming yang didukung rxResource. Fungsi stream menerima konteks Observable dan harus mengembalikan sebuah 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($any($event.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 },
}),
});
}Berbeda dengan httpResource, rxResource memberikan kendali penuh atas pipeline Observable. Operator seperti debounceTime atau retry dapat dirangkai di dalam stream. Namun, httpResource menangani kasus paling umum (satu permintaan GET) dengan lebih sedikit kode.
Siap menguasai wawancara Angular Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Pelacakan Status: Literal String Menggantikan Enum
ResourceStatus adalah tipe union string. Enam nilai yang mungkin memberikan wawasan rinci tentang siklus hidup resource:
| Status | Arti |
|---|---|
'idle' | params mengembalikan undefined, tidak ada permintaan yang dikirim |
'loading' | Permintaan pertama sedang berlangsung |
'reloading' | Permintaan berikutnya setelah keberhasilan sebelumnya |
'resolved' | Data tersedia di value() |
'error' | Permintaan gagal, error() berisi error |
'local' | Nilai diatur secara lokal melalui .set() atau .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();
},
});
}Mengembalikan undefined dari params menetapkan status menjadi 'idle' dan mencegah loader dijalankan. Pola ini cocok untuk pengambilan data bersyarat: tampilkan petunjuk hingga pengguna memberikan masukan, lalu muat data.
Memanggil value() pada resource berstatus 'error' melempar exception saat runtime. Selalu lindungi pembacaan dengan hasValue() atau periksa status() sebelum mengakses value(). Ini adalah perubahan dari Angular 19, di mana value() mengembalikan undefined saat error.
Pertanyaan Wawancara Angular httpResource
Resource API menjadi topik standar dalam pertanyaan wawancara Angular. Berikut pertanyaan yang menguji pemahaman nyata, melampaui kefasihan permukaan terhadap API.
T: Masalah apa yang diselesaikan httpResource yang tidak diselesaikan resource()?
resource() menggunakan fetch() atau loader berbasis promise mana pun, melewati HttpClient Angular. Ini berarti interceptor (untuk token autentikasi, logging, penanganan error) tidak berlaku. httpResource menggunakan HttpClient secara internal, sehingga interceptor, utilitas pengujian (HttpTestingController), dan fitur seperti withFetch() berfungsi tanpa konfigurasi tambahan.
T: Kapan rxResource sebaiknya dipilih dibanding httpResource?
rxResource memberikan kendali penuh atas Observable melalui fungsi stream-nya. Pilih ia ketika pipeline data membutuhkan operator RxJS: melakukan debounce pada masukan pencarian, mencoba ulang permintaan gagal dengan exponential backoff, atau menggabungkan beberapa stream dengan combineLatest. Untuk permintaan GET sederhana, httpResource membutuhkan lebih sedikit kode.
T: Bagaimana Angular menangani permintaan bersamaan ketika sebuah signal berubah dengan cepat?
Ketiga varian resource membatalkan permintaan yang sedang berjalan ketika params menghasilkan nilai baru. Untuk httpResource dan resource(), AbortSignal membatalkan fetch yang mendasarinya. Untuk rxResource, Angular berhenti berlangganan dari Observable sebelumnya. Ini mencegah respons usang menimpa data yang baru.
T: Apa tujuan status 'local'?
Memanggil .set() atau .update() pada resource mengubah nilainya secara lokal tanpa memicu loader. Status beralih ke 'local', menandakan bahwa nilai saat ini tidak berasal dari server. Ini mendukung pembaruan UI optimistis: UI mencerminkan perubahan seketika sementara permintaan mutasi terpisah berjalan.
T: Bagaimana integrasi Zod bekerja dengan httpResource?
Opsi parse menerima fungsi apa pun dengan signature (data: unknown) => T. Ketika respons HTTP tiba, httpResource meneruskan JSON yang sudah diurai melalui parse sebelum menetapkan value(). Jika parse melempar exception (misalnya ZodError), resource beralih ke status 'error'. Tipe kembalian parse menentukan tipe TypeScript dari value(), memberikan keamanan runtime sekaligus tipe saat kompilasi dari satu definisi schema.
T: Bagaimana chain() menangani error dari resource upstream?
Ketika menggunakan chain(upstreamResource) dalam fungsi params resource, resource yang bergantung tidak menjalankan loader-nya jika resource upstream sedang loading, idle, atau dalam status error. Jika resource upstream mengalami error, resource yang bergantung beralih ke status error dengan ResourceDependencyError. Error ini menyertakan dependency (resource upstream) dan cause (error upstream yang sebenarnya), memungkinkan Anda membedakan antara "permintaan saya gagal" dan "permintaan dependensi saya gagal".
Untuk pendalaman tentang signal Angular dan bagaimana mereka terintegrasi dengan framework secara lebih luas, panduan signal mencakup computed signal, effect, dan model reaktivitas.
Migrasi dari Subscription HttpClient ke httpResource
Aplikasi Angular yang sudah ada umumnya mengambil data dengan subscription HttpClient di dalam ngOnInit, atau menggunakan AsyncPipe dengan Observable. Migrasi ke httpResource mengikuti pola yang dapat diprediksi:
// 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()
}Migrasi ini menghilangkan boilerplate pengelolaan siklus hidup. Pembersihan subscription terjadi otomatis ketika komponen dihancurkan. Status loading dan error sudah terpasang di dalam resource, tidak diperlukan flag boolean terpisah.
Untuk aplikasi yang sudah menggunakan komponen standalone, migrasinya lugas: ganti injeksi HttpClient dan logika subscription dengan satu deklarasi httpResource.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Sumber
- Dokumentasi Angular Resource API โ panduan resmi tentang resource(), rxResource(), dan httpResource()
- What's new in Angular 22.0 โ liputan Ninja Squad tentang Resource API yang stabil dan helper chain()
- Panduan interceptor HTTP Angular โ cara kerja interceptor dengan httpResource
Poin Penting untuk Angular Resource API
httpResourcemenggantikan subscriptionHttpClientmanual dengan satu deklarasi reaktif yang menangani loading, error, dan pembatalan secara otomatis- Gunakan
resource()untuk API berbasis promise,rxResource()untuk pipeline Observable dengan operator RxJS, danhttpResource()untuk panggilan HTTP standar dengan dukungan interceptor - Helper
chain()(Angular 22+) memungkinkan pemuatan resource bergantung dengan propagasi status otomatis; jika upstream gagal, resource yang bergantung mendapatkanResourceDependencyError - Nilai status berupa literal string (
'idle','loading','resolved','error','reloading','local') - Opsi
parsepadahttpResourcemengintegrasikan Zod atau Valibot untuk validasi schema runtime yang juga mengarahkan tipe TypeScript - Memanggil
value()pada resource dalam status error melempar exception; selalu lindungi denganhasValue()atau periksastatus()terlebih dahulu - Semua varian resource membatalkan permintaan yang sedang berjalan secara otomatis ketika dependensi berubah, mencegah race condition tanpa logika pembatalan manual
Bisakah kamu menemukan bug di Angular?
Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Ditulis oleh
Anthony Fillion-MailletPendiri SharpSkill
Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.
Diperbarui 13 Oktober 2026
Tag
Bagikan
Artikel terkait

NgRx Signal Store vs Classic NgRx di 2026: Mana yang Harus Dipilih?
Perbandingan lengkap NgRx Signal Store dan Classic NgRx untuk manajemen state Angular. Pelajari kapan menggunakan masing-masing pendekatan dengan contoh kode praktis.

RxJS di Angular 2026: Operator, Subject, dan Interop Signals
RxJS di Angular 2026: kuasai operator, Subject, dan pola interop Signals yang dipakai developer Angular di produksi, plus pertanyaan wawancara yang paling sering muncul.

Dependency Injection Lanjutan di Angular 2026: Providers, Tokens, dan Pertanyaan Interview
Pelajari sistem dependency injection Angular secara mendalam termasuk strategi provider, InjectionToken, injector hierarkis, dan pertanyaan interview umum untuk developer Angular berpengalaman.