# Angular 20 em 2026: Resource API, httpResource e perguntas de entrevista > O Angular 20 introduz o httpResource e estabiliza a Resource API para a busca de dados baseada em signals. Um tutorial prático sobre resource(), rxResource(), httpResource(), a validação com Zod e as perguntas de entrevista mais comuns. - Published: 2026-05-30 - Updated: 2026-06-06 - Author: SharpSkill - Tags: angular, angular-20, resource-api, httpresource, signals, typescript, tutorial - Reading time: 10 min --- O Angular 20 coloca a [Resource API](https://angular.dev/guide/signals/resource) e o `httpResource` no centro da busca de dados baseada em signals. Essas APIs experimentais substituem os verbosos padrões de subscrição do `HttpClient` por primitivas reativas que acompanham automaticamente os estados de carregamento, erro e resolução. > **O que muda no Angular 20** > > A Resource API renomeia `request` para `params` e `loader` para `stream` (no caso do `rxResource`). Os valores de status agora são literais de string (`'idle'`, `'loading'`, `'resolved'`, `'error'`, `'reloading'`, `'local'`) em vez de enumerações numéricas. O `httpResource` é construído sobre o `HttpClient` e oferece suporte nativo a interceptors e à validação com Zod. ## As três variantes de Resource no Angular 20 O Angular 20 oferece três maneiras de carregar dados assíncronos como signals. Cada uma atende a um caso de uso diferente, mas todas compartilham o mesmo modelo reativo: declarar dependências, definir um loader e consumir o resultado por meio de signals. - **`resource()`** funciona com Promises. Ideal ao usar `fetch()` ou qualquer API baseada em promessas. - **`rxResource()`** funciona com Observables. A escolha certa quando operadores RxJS como `debounceTime`, `retry` ou `switchMap` são necessários. - **`httpResource()`** encapsula diretamente o `HttpClient` do Angular. Interceptors, utilitários de teste e validação de schema funcionam sem configuração adicional. A diferença essencial entre o `httpResource` e os outros dois: o `httpResource` usa o `HttpClient` por baixo dos panos, o que significa que os [interceptors](https://angular.dev/guide/http/interceptors) existentes continuam funcionando. A API `resource()` original ignorava completamente o `HttpClient`, um ponto de atrito importante no Angular 19. ## Construindo um perfil de usuário com resource() A função `resource()` aceita uma função de cálculo `params` e uma função `loader`. Quando os signals dentro de `params` mudam, o loader é reexecutado automaticamente. ```typescript // user-profile.component.ts import { Component, signal, resource } from '@angular/core'; interface User { id: number; name: string; email: string; } @Component({ selector: 'app-user-profile', template: ` @if (userResource.hasValue()) {

{{ userResource.value().name }}

{{ userResource.value().email }}

} @else if (userResource.isLoading()) {

Loading profile...

} @else if (userResource.error()) {

Failed to load user

} `, }) export class UserProfileComponent { userId = signal(1); // params produces the reactive dependency // loader receives it and returns a Promise userResource = resource({ 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 } } ``` O parâmetro `abortSignal` permite que o Angular cancele requisições em andamento quando `userId` muda antes de a requisição anterior terminar. Isso evita condições de corrida sem gerenciamento manual de subscrições. ## Busca reativa de dados com httpResource O `httpResource` elimina o código repetitivo ao combinar a declaração da URL e a execução HTTP em uma única chamada. Ele retorna um `HttpResourceRef` que expõe `value`, `isLoading`, `error`, `status` e `headers` como signals. ```typescript // product-list.component.ts 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) {

{{ product.name }}

{{ product.price | currency }}
} } @else if (products.isLoading()) {

Loading products...

} `, }) export class ProductListComponent { category = signal('electronics'); // httpResource re-fetches whenever category() changes products = httpResource(() => ({ url: '/api/products', params: { category: this.category() }, })); filterByCategory(cat: string) { this.category.set(cat); // pending request is cancelled, new one starts } } ``` Vários detalhes importam aqui. A função passada ao `httpResource` retorna um objeto de configuração de requisição. O Angular acompanha as leituras de signals dentro dessa função, então alterar `category` dispara uma nova requisição GET. Se já houver uma requisição em andamento, o Angular a cancela antes de iniciar a nova. > **httpResource é apenas para leituras** > > O `httpResource` foi projetado para a busca de dados (requisições GET). Usá-lo em operações POST, PUT ou DELETE é inseguro, porque o cancelamento da requisição poderia abortar uma mutação no meio do caminho. Para operações de escrita, usar o `HttpClient` diretamente ou encapsular as mutações em um método de serviço. ## Validação de schema com Zod e httpResource As respostas de serviços externos podem divergir do formato esperado. A opção `parse` do `httpResource` integra bibliotecas de validação de schema como o [Zod](https://zod.dev/) para detectar incompatibilidades em tempo de execução, em vez de propagar silenciosamente dados corrompidos. ```typescript // order.component.ts 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; @Component({ selector: 'app-order', template: ` @if (order.hasValue()) {

Order #{{ order.value().id }}

Status: {{ order.value().status }}

Total: {{ order.value().total | currency }}

} @else if (order.error()) {

Invalid order data received

} `, }) export class OrderComponent { orderId = signal(42); // parse validates the response before exposing it as a signal order = httpResource( () => `/api/orders/${this.orderId()}`, { parse: OrderSchema.parse } ); } ``` Quando a API retorna dados que não correspondem ao `OrderSchema`, a resource passa ao status `'error'`. O tipo de retorno da função `parse` também determina o tipo TypeScript de `value()`, então as definições de schema cumprem um papel duplo: validadores em tempo de execução e geradores de tipos. ## rxResource com stream e params no Angular 20 O Angular 20 renomeia `loader` para `stream` e `request` para `params` no `rxResource`. Essa mudança alinha a nomenclatura à semântica de streaming que o `rxResource` oferece. A função `stream` recebe um contexto de Observable e deve retornar um Observable. ```typescript // search.component.ts 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: ` @if (results.isLoading()) {

Searching...

} @if (results.hasValue()) { @for (item of results.value(); track item.id) {
{{ item.title }}
} } `, }) export class SearchComponent { private http = inject(HttpClient); query = signal(''); // params (was "request") provides the reactive input // stream (was "loader") returns an Observable results = rxResource({ params: () => this.query(), stream: ({ params: q }) => this.http.get('/api/search', { params: { q }, }), }); } ``` Ao contrário do `httpResource`, o `rxResource` oferece controle total sobre o pipeline de Observable. Operadores como `debounceTime` ou `retry` podem ser encadeados dentro de `stream`. No entanto, o `httpResource` resolve o caso mais comum (uma única requisição GET) com menos código. ## Acompanhamento de status: literais de string substituem as enumerações O Angular 20 transforma o `ResourceStatus` de uma enumeração numérica em um tipo de união de strings. Os seis valores possíveis oferecem uma visão detalhada do ciclo de vida da resource: | Status | Significado | |---|---| | `'idle'` | `params` retornou `undefined` — nenhuma requisição emitida | | `'loading'` | Primeira requisição em andamento | | `'reloading'` | Requisição subsequente após um sucesso anterior | | `'resolved'` | Dados disponíveis em `value()` | | `'error'` | A requisição falhou — `error()` contém o erro | | `'local'` | Valor definido localmente via `.set()` ou `.update()` | ```typescript // status-demo.component.ts import { Component, signal, resource } from '@angular/core'; @Component({ selector: 'app-status-demo', template: `

Status: {{ data.status() }}

@switch (data.status()) { @case ('loading') { } @case ('reloading') { } @case ('resolved') { } @case ('error') { } @case ('idle') {

Select a filter to load data

} } `, }) export class StatusDemoComponent { filter = signal(undefined); data = resource({ params: () => this.filter(), loader: async ({ params: f, abortSignal }) => { const res = await fetch(`/api/data?filter=${f}`, { signal: abortSignal }); return res.json(); }, }); } ``` Retornar `undefined` a partir de `params` define o status como `'idle'` e impede que o loader seja executado. Esse padrão funciona bem para a busca condicional de dados: exibir um aviso até que o usuário forneça uma entrada e, então, carregar os dados. > **Acessar value() no estado de erro** > > Desde o Angular 20, chamar `value()` em uma resource com status `'error'` lança uma exceção em tempo de execução. Sempre proteger as leituras com `hasValue()` ou verificar `status()` antes de acessar `value()`. Trata-se de uma mudança incompatível em relação ao Angular 19, em que `value()` retornava `undefined` em caso de erro. ## Perguntas de entrevista sobre httpResource no Angular 20 A Resource API está se tornando um tema padrão das [perguntas de entrevista de Angular](/blog/angular/angular-19-interview-questions-signals-ssr-must-know). Estas perguntas avaliam uma compreensão real, além da familiaridade superficial com a API. **P: Qual problema o `httpResource` resolve que o `resource()` não resolve?** O `resource()` usa `fetch()` ou qualquer loader baseado em promessas, ignorando o `HttpClient` do Angular. Isso significa que os interceptors (para tokens de autenticação, logging, tratamento de erros) não se aplicam. O `httpResource` usa o `HttpClient` internamente, então interceptors, utilitários de teste (`HttpTestingController`) e recursos como `withFetch()` funcionam sem configuração adicional. **P: Quando o `rxResource` deve ser preferido em relação ao `httpResource`?** O `rxResource` oferece controle total sobre o Observable por meio da sua função `stream`. Vale escolhê-lo quando o pipeline de dados exige operadores RxJS: aplicar debounce à entrada de busca, repetir requisições falhas com backoff exponencial ou combinar vários fluxos com `combineLatest`. Para requisições GET simples, o `httpResource` exige menos código. **P: Como o Angular lida com requisições concorrentes quando um signal muda rapidamente?** As três variantes de resource cancelam as requisições em andamento quando `params` produz um novo valor. Para o `httpResource` e o `resource()`, o `AbortSignal` cancela o fetch subjacente. Para o `rxResource`, o Angular cancela a subscrição do Observable anterior. Isso impede que respostas obsoletas sobrescrevam dados atualizados. **P: Qual é o propósito do status `'local'`?** Chamar `.set()` ou `.update()` em uma resource altera seu valor localmente sem disparar o loader. O status passa a `'local'`, indicando que o valor atual não veio do servidor. Isso facilita as atualizações otimistas da interface: a UI reflete a mudança imediatamente enquanto uma requisição de mutação separada é executada. **P: Como funciona a integração do Zod com o `httpResource`?** A opção `parse` aceita qualquer função com a assinatura `(data: unknown) => T`. Quando a resposta HTTP chega, o `httpResource` passa o JSON analisado por `parse` antes de definir `value()`. Se `parse` lançar uma exceção (por exemplo, `ZodError`), a resource passa ao status `'error'`. O tipo de retorno de `parse` determina o tipo TypeScript de `value()`, oferecendo segurança em tempo de execução e tipos em tempo de compilação a partir de uma única definição de schema. Para aprofundar nos [signals do Angular](/technologies/angular/interview-questions/angular-signals) e em como eles se integram ao framework de modo mais amplo, o módulo de signals cobre os computed signals, os effects e o modelo de reatividade. ## Migrando de subscrições HttpClient para httpResource As aplicações Angular existentes geralmente buscam dados com subscrições de `HttpClient` dentro de `ngOnInit`, ou usam o `AsyncPipe` com Observables. A migração para o `httpResource` segue um padrão previsível: ```typescript // BEFORE: manual subscription in ngOnInit @Component({ /* ... */ }) export class BeforeComponent implements OnInit, OnDestroy { private http = inject(HttpClient); private destroy$ = new Subject(); users: User[] = []; loading = false; error: string | null = null; ngOnInit() { this.loading = true; this.http.get('/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(() => '/api/users'); // No ngOnInit, no Subject, no manual unsubscribe // Template uses users.value(), users.isLoading(), users.error() } ``` A migração elimina o código repetitivo de gerenciamento do ciclo de vida. A limpeza das subscrições ocorre automaticamente quando o componente é destruído. Os estados de carregamento e erro estão integrados à resource: não são necessárias flags booleanas separadas. Para aplicações que já usam [componentes standalone](/blog/angular/angular-standalone-components-migration-best-practices), a migração é direta: substituir a injeção do `HttpClient` e a lógica de subscrição por uma única declaração `httpResource`. ## Conclusão - O `httpResource` substitui as subscrições manuais ao `HttpClient` por uma única declaração reativa que gerencia automaticamente o carregamento, o erro e o cancelamento - Usar `resource()` para APIs baseadas em promessas, `rxResource()` para pipelines de Observable com operadores RxJS e `httpResource()` para chamadas HTTP padrão com suporte a interceptors - O Angular 20 renomeia `request` para `params` e `loader` para `stream` no `rxResource` — atualize o código existente de acordo - Os valores de status agora são literais de string (`'idle'`, `'loading'`, `'resolved'`, `'error'`, `'reloading'`, `'local'`), substituindo as enumerações numéricas do Angular 19 - A opção `parse` do `httpResource` integra Zod ou Valibot para uma validação de schema em tempo de execução que também conduz os tipos TypeScript - Chamar `value()` em uma resource no estado de erro lança uma exceção no Angular 20 — sempre proteja com `hasValue()` ou verifique `status()` primeiro - Todas as variantes de resource cancelam automaticamente as requisições em andamento quando as dependências mudam, evitando condições de corrida sem lógica de cancelamento manual --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pt/blog/angular/angular-20-resource-api-httpresource-tutorial