I'm trying to use the new Angular httpResource
. So I created a service as follows
@Injectable({ providedIn: 'root' })
export class MyService {
resourceConfig = signal<Partial<ResourceConfig>>({})
response = httpResource(() => ({
url: this.resourceConfig().path,
method: this.resourceConfig().method,
body: this.resourceConfig.payload
};
})
connect(payload: unknown) {
this.resourceConfig.set({
path: '/connect',
method: 'POST',
payload
})
}
}
This code works, the call to the connect
endpoint is executed, but then I don't get anything back. For testing I've checked all the response
signals in the component that calls connect
:
export class MyConnectComponent {
private service = inject(MyService)
connectResponseFn = effect(() => {
const status = this.service.response.status(). // -> 2
const error = this.service.response.error(). // -> undefined
const resp = this.service.response.value(). // -> undefined
const code = this.service.response.statusCode() // -> undefined
})
ngOnInit() {
this.service.connect({test: true})
}
}
How can I get responses in this situation?
You should not execute the inner properties like path
, method
or payload
since they are not signals.
@Injectable({ providedIn: 'root' })
export class MyService {
resourceConfig = signal<Partial<ResourceConfig>>({})
response = httpResource(() => ({
url: this.resourceConfig().path,
method: this.resourceConfig().method,
body: this.resourceConfig().payload,
})
connect(payload: unknown) {
this.resourceConfig.set({
path: '/connect',
method: 'POST',
payload
})
}
}
You can handle errors, by directly checking the error message in the HTML and show the error.
@let error = getError(response.error());
@if(error) {
{{error.message | json}}
} @else if (response.isLoading()) {
Loading...
} @else {
{{response.value() | json }}
}
The problem is error
method is that it returns unknown
but to access the error message, we have to type it to HttpErrorResponse
, we use a function to type it along with @let
operator.
getError(error: any) {
return error as HttpErrorResponse;
}
You can also use the status
property of error, to show different message on each error code.
@let error = getError(response.error());
@if(error) {
@switch(error.status) {
@case (401) {
Access Unauthorized
}@case (404) {
API Not Found
} @default {
{{error.status}} - {{error.message}}
}
}
}
Below is a working Stackblitz highlighting the error handling mechanism:
import { Component, effect, inject, signal, Injectable } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import {
HttpErrorResponse,
httpResource,
HttpResourceRequest,
provideHttpClient,
} from '@angular/common/http';
import { JsonPipe } from '@angular/common';
export interface ResourceConfig {
path?: string;
method?: string;
payload?: any;
}
@Injectable({ providedIn: 'root' })
export class MyService {
resourceConfig = signal<ResourceConfig>({});
response = httpResource(
() =>
({
url: this.resourceConfig()!.path,
method: this.resourceConfig()!.method,
body: this.resourceConfig()!.payload,
} as HttpResourceRequest)
);
connect(payload: unknown) {
this.resourceConfig.set({
path: '/connect',
method: 'POST',
payload,
});
}
}
@Component({
selector: 'app-root',
imports: [JsonPipe],
template: `
@let error = getError(response.error());
@if(error) {
@switch(error.status) {
@case (401) {
Access Unauthorized
}@case (404) {
API Not Found
} @default {
{{error.status}} - {{error.message}}
}
}
} @else if (response.isLoading()) {
Loading...
} @else {
{{response.value() | json }}
}
`,
})
export class App {
private service = inject(MyService);
get response() {
return this.service.response;
}
connectResponseFn = effect(() => {
const status = this.service.response.status(); // -> 2
const error = this.service.response.error(); // -> undefined
const resp = this.service.response.value(); // -> undefined
const code = this.service.response.statusCode(); // -> undefined
});
ngOnInit() {
this.service.connect({ test: true });
}
getError(error: any) {
return error as HttpErrorResponse;
}
}
bootstrapApplication(App, {
providers: [provideHttpClient()],
});