
Data fetching has always been a tricky balancing act in Angular:
Where should the logic live — inside the component or abstracted elsewhere?
With the introduction of httpResource in Angular 19, this question is more relevant than ever. httpResource provides a reactive, signal-driven way to work with HTTP calls — but if misused, it can quickly tangle business logic with UI code.
In this article, we’ll explore what httpResource does, the temptation of in-component usage, and why service-based abstraction is the key to maintainable, scalable applications.
Why httpResource Matters
At its core, httpResource is a reactive wrapper around Angular’s HttpClient.
Instead of manually subscribing to Observables, httpResource integrates seamlessly with the signals ecosystem — meaning its results can be consumed by computed, effect, linkedSignal, or directly in templates.
Some key properties:
-
Eager execution: Unlike
HttpClient, which only fires on subscription,httpResourceeagerly triggers requests when its reactive dependencies change. - Automatic cancellation: If dependencies change mid-request, the in-flight request is canceled and a new one is issued.
-
Full
HttpClientsupport: Interceptors and all other features still apply.
Example of a simple reactive resource:
userId = input<string>();
user = httpResource(() => `/api/user/${userId()}`);
Whenever userId changes, a fresh request is dispatched automatically.
The Temptation: Quick In-Component Usage
The most straightforward way to use httpResource is directly in a component:
@Component({ /* ... */ })
export class MyUserComponent {
userId = input<string>();
userResource = httpResource(() => `/api/user/${this.userId()}`);
}
It works — but this convenience comes at a cost.
By mixing data-fetching logic into the component:
- You violate single responsibility — components should focus on rendering and interaction, not on orchestrating HTTP calls.
- Business logic becomes scattered and harder to reuse.
- Testing gets messy: mocking component state and HTTP behavior together is more complex.
For tiny apps or prototypes, this pattern might be acceptable. However, in real-world applications, it creates tight coupling and long-term maintenance headaches.
The Better Way: Abstract httpResource into Services
A cleaner approach is to define httpResource inside dedicated services, not components.
This service-based pattern offers several advantages:
- Separation of concerns: Components stay UI-focused while services handle data logic.
- Reusability: Multiple components can consume the same resource logic.
- Simpler testing: Service logic can be tested independently of UI behavior.
- Consistency: Teams can share and maintain standardized resource definitions.
Example: Service-Based Resource
// user.service.ts
@Injectable()
export class UserService {
// A shared resource for all consumers
readonly usersResource = httpResource(() => `/api/users`);
// Factory method for reactive user fetching
createUserResource($userId: Signal<string>) {
return httpResource(() => (
$userId() ? `/api/user/${$userId()}` : undefined
));
}
}
// user-details.component.ts
@Component({ /* ... */ })
export class UserDetailsComponent {
readonly userId = input<string>();
readonly #userService = inject(UserService);
readonly userResource = this.#userService.createUserResource(this.userId);
}
When Might In-Component Be Okay?
To keep this balanced:
- Demos, prototypes, or playgrounds — quick feedback matters more than clean architecture.
- Truly one-off fetches — where introducing a service would be unnecessary overhead.
But beyond these cases, service abstraction almost always pays off.
Conclusion: Future-Proof Your Angular Apps
Angular’s httpResource is a big step forward for reactive data fetching. But its power can become a liability if used naively inside components.
By moving your resource definitions into services, you get:
- Cleaner components
- Reusable data logic
- Easier testing and scaling
👉 Next time you reach for httpResource, ask: “Should this live in a component — or does it belong in a service?”
Chances are, the service wins.
This simple shift will prepare your codebase for growth, teamwork, and the evolving Angular ecosystem.
Top comments (0)