Angular has always been a powerful framework for building web applications, but handling asynchronous operations, especially HTTP requests, has sometimes felt clunky. The upcoming Angular v19, scheduled for release in November 2024, aims to change that with two new experimental APIs: resource
and rxResource
. These features promise to revolutionize how we handle HTTP requests by providing a more reactive and streamlined approach.
What are Resource and RxResource?
At their core, these new APIs provide a way to handle asynchronous operations with better integration into Angular's signals system:
- resource: Request an asynchronous operation that returns a Promise and get the result as a writable signal
- rxResource: Request an asynchronous operation that returns an Observable and get the result as a writable signal
Both APIs are designed to make HTTP requests more reactive and easier to manage within Angular's ecosystem.
Basic Usage of Resource
Let's look at how to use the new resource
API for a basic HTTP request:
// Using resource with fetch (Promise-based)
const products = resource({
loader: async () => {
const response = await fetch('https://swapi.dev/api/vehicles/');
return response.json();
}
});
When this resource is created, it immediately issues the HTTP request. The resource
function returns a "resource ref" object, not directly a signal.
RxResource for Observable-based Operations
If you're more familiar with HttpClient and observables, the rxResource
API offers a more comfortable approach:
// Inject HttpClient
private http = inject(HttpClient);
// Using rxResource with HttpClient (Observable-based)
const products = rxResource({
loader: () => this.http.get<ProductResponse>('https://swapi.dev/api/vehicles/')
});
The rxResource
automatically handles subscription and unsubscription to the observable. It's important to note that it only considers the first emission, similar to using RxJS's firstValueFrom
operator.
Accessing Resource Values and Status
A resource ref has several properties that are signals:
value
: The result of the async operationstatus
: The current status of the operationerror
: Any error information
Example of tracking resource status:
effect(() => {
console.log("Status:", ResourceStatus[products.status()]);
console.log("Value:", products.value());
});
The status can be one of the following (from the ResourceStatus enum):
loading
: The async operation is in progressresolved
: The async operation completed successfullyerror
: The async operation failedlocal
: The data has been updated locally
Working with Query Parameters
One of the most powerful features of the new Resource APIs is their reactivity to signal changes, making them perfect for query parameters:
Single Parameter
// Create a signal for the selected product ID
const selectedProductId = signal<number | null>(null);
// Define a resource that reacts to the ID
const product = rxResource({
request: () => selectedProductId,
loader: (productId) => this.http.get<Product>(`https://swapi.dev/api/vehicles/${productId}`)
});
Multiple Parameters
// Create signals for multiple parameters
const selectedProductId = signal<number | null>(null);
const color = signal<string | null>(null);
// Define a resource that reacts to both signals
const product = rxResource({
request: () => ({ id: selectedProductId(), color: color() }),
loader: (request) => this.http.get<Product>(
`https://swapi.dev/api/vehicles/${request.id}?color=${request.color}`
)
});
When any of the signals referenced in the request
function change, the resource automatically re-executes the loader function.
Local Updates
Since the resource's value
property is a writable signal, you can update it locally:
function onUpdate(): void {
// Update the product data locally
product.value.update(currentValue => {
if (currentValue) {
return {
...currentValue,
cost_in_credits: '1000000'
};
}
return currentValue;
});
}
After the update, the status of the resource changes to local
, indicating that the data has been modified locally.
Important Considerations
There are some important things to keep in mind when using these new APIs:
Read Operations Only: The documentation explicitly states that resource and rxResource are intended for read operations, not mutations. This is because they can cancel in-progress loads when destroyed or when a new request object becomes available, which could prematurely abort mutations.
Request vs. Loader: Signals defined in the
request
function are tracked for changes, but those referenced in theloader
function are not. Only changes to signals in the request cause the loader to re-execute.Cancellation: If data is updated while a request is in progress, that request is cancelled, and the update takes precedence.
Conclusion
The new resource
and rxResource
APIs in Angular v19 provide a powerful way to handle asynchronous operations with better integration into Angular's reactivity system. They allow for:
- Reactive async code that responds to signal changes
- Using signals as query parameters
- Reading HTTP responses as writable signals
- Tracking request status and errors
- Cancelling requests when needed
- Reloading requests automatically
While these features will be experimental in Angular v19, they represent a significant step forward in how Angular handles asynchronous operations. If you're working with Angular, these new APIs are definitely worth exploring when v19 is released in November.
References
- Angular v19 Documentation (coming soon)
- Angular GitHub Repository