IMPORTANT: httpResource
is experimental. It's ready for you to try, but it might change before it is stable.
httpResource
is a reactive wrapper around HttpClient
that gives you the request status and response as signals. You can thus use these signals with computed
, effect
, linkedSignal
, or any other reactive API. Because it's built on top of HttpClient
, httpResource
supports all the same features, such as interceptors.
For more about Angular's resource
pattern, see Async reactivity with resource
.
Using httpResource
TIP: Make sure to include provideHttpClient
in your application providers. See Setting up HttpClient for details.
You can define an HTTP resource by returning a url:
userId = input.required<string>();user = httpResource(() => `/api/user/${userId()}`); // A reactive function as argument
httResource
is reactive, meaning that whenever one of the signal it depends on changes (like userId
), the resource will emit a new http request.
If a request is already pending, the resource cancels the outstanding request before issuing a new one.
HELPFUL: httpResource
differs from the HttpClient
as it initiates the request eagerly. In contrast, the HttpClient
only initiates requests upon subscription to the returned Observable
.
For more advanced requests, you can define a request object similar to the request taken by HttpClient
.
Each property of the request object that should be reactive should be composed by a signal.
user = httpResource(() => ({ url: `/api/user/${userId()}`, method: 'GET', headers: { 'X-Special': 'true', }, params: { 'fast': 'yes', }, reportProgress: true, withCredentials: true, transferCache: true,}));
TIP: Avoid using httpResource
for mutations like POST
or PUT
. Instead, prefer directly using the underlying HttpClient
APIs.
The signals of the httpResource
can be used in the template to control which elements should be displayed.
@if(user.hasValue()) { <user-details user="[user.value()]">} @else if (user.error()) { <div>Could not load user information</div>} @else if (user.isLoading()) { <div>Loading user info...</div>}
HELPFUL: Reading the value
signal on a resource
that is in error state throws at runtime. It is recommended to guard value
reads with hasValue()
.
Response types
By default, httpResource
returns and parses the response as JSON. However, you can specify alternate return with additional functions on httpResource
:
httpResource.text(() => ({ … })); // returns a string in value()httpResource.blob(() => ({ … })); // returns a Blob object in value()httpResource.arrayBuffer(() => ({ … })); // returns an ArrayBuffer in value()
Response parsing and validation
When fetching data, you may want to validate responses against a predefined schema, often using popular open-source libraries like Zod or Valibot. You can integrate validation libraries like this with httpResource
by specifying a parse
option. The return type of the parse
function determines the type of the resource's value
.
The following example uses Zod to parse and validate the response from the StarWars API. The resource is then typed the same as the output type of Zod’s parsing.
const starWarsPersonSchema = z.object({ name: z.string(), height: z.number({ coerce: true }), edited: z.string().datetime(), films: z.array(z.string()),});export class CharacterViewer { id = signal(1); swPersonResource = httpResource( () => `https://swapi.dev/api/people/${this.id()}`, { parse: starWarsPersonSchema.parse } );}
Testing an httpResource
Because httpResource
is a wrapper around HttpClient
, you can test httpResource
with the exact same APIs as HttpClient
. See HttpClient Testing for details.
The following example shows a unit test for code using httpResource
.
TestBed.configureTestingModule({ providers: [ provideHttpClient(), provideHttpClientTesting(), ],});const id = signal(0);const mockBackend = TestBed.inject(HttpTestingController);const response = httpResource(() => `/data/${id()}`, {injector: TestBed.inject(Injector)});TestBed.tick(); // Triggers the effectconst firstRequest = mockBackend.expectOne('/data/0');firstRequest.flush(0);// Ensures the values are propagated to the httpResourceawait TestBed.inject(ApplicationRef).whenStable();expect(response.value()).toEqual(0);