Configuração atual e envio por subscrição
Na documentação Angular 22 consultada, HttpClient está disponível para injeção por omissão desde a versão 21. provideHttpClient permite configurar funcionalidades, incluindo interceptors; não deve ser apresentado como prova de que ocorreu um pedido.
O cliente usa fetch por omissão na base atual. Cada método como get devolve um Observable cold: a criação descreve o pedido, e a subscrição inicia-o. Duas subscrições independentes ao mesmo Observable podem originar dois pedidos.
Se o código e o template subscrevem separadamente, procura aí a duplicação antes de a atribuir a um bug do backend.
Tipos declarados e dados aceites
O genérico de http.get<Order> informa o código TypeScript sobre o tipo esperado. Não verifica que o JSON recebido tem esse tipo, não converte strings numéricas e não confirma autorização. Para dados de estrutura incerta, recebe unknown e aplica uma verificação explícita antes de construir o modelo aceite.
O exemplo confirma objeto não nulo, presença de total numérico e finitude antes de usar toFixed. Esta verificação é limitada ao campo necessário ao exemplo; não certifica todos os possíveis atributos de uma encomenda nem regras comerciais que não foram definidas.
A intenção mais recente e switchMap
switchMap projeta cada valor de entrada num Observable interno e troca a subscrição anterior pela nova. No exemplo, escolhas sucessivas de id representam leituras e só a resposta da escolha atual interessa. Desativar a subscrição HTTP anterior aborta um pedido ainda em curso no cliente, mas não prova que um servidor desfez trabalho já realizado.
Por isso, não generalizes esta política para operações de escrita que têm de ser concluídas ou reconciliadas. Primeiro define se o evento novo substitui o anterior, se deve esperar ou se os dois resultados continuam relevantes.
Recuperar o pedido ou terminar o fluxo
catchError substitui um fluxo que terminou com erro pelo Observable devolvido pela função de tratamento. Se estiver depois de switchMap e devolver um fallback finito, pode terminar a subscrição ao fluxo externo após esse fallback. No exemplo, está dentro do pedido: o erro produz um estado de falha para essa escolha e a subscrição às escolhas futuras permanece.
Esta colocação é uma decisão de recuperação, não apenas de apresentação da mensagem. Uma falha de validação lançada durante map segue o mesmo caminho de erro e não é confundida com um resultado ready.
Parâmetros e interceptors imutáveis
HttpParams e HttpHeaders usam atualizações imutáveis: set ou append devolvem uma nova instância, que deve ser conservada ou encadeada. Ignorar o retorno não altera o original. Interceptors funcionais configurados com withInterceptors seguem a ordem declarada no percurso do pedido; cada um encaminha a versão pretendida através de next.
Para alterar headers de HttpRequest, usa clone com os valores apropriados. O body não tem garantia de proteção contra mutação profunda. Se o mesmo pedido atravessar novamente a cadeia, uma alteração cumulativa ao body pode ser aplicada outra vez.
Falha, timeout e repetição
HttpErrorResponse comunica falhas através do canal de erro. Erros de rede e timeout usam status 0; respostas de erro do backend transportam o status recebido. A opção timeout delimita a execução HTTP ao backend e não toda a cadeia de interceptors e processamento.
Retry volta a subscrever e pode reenviar o pedido. Num POST cuja resposta se perdeu após commit, repetir pode duplicar o efeito. A política precisa de idempotência, consulta de resultado ou reconciliação conforme o contrato remoto.
Um operador RxJS não pode, por si só, estabelecer exatamente um efeito num sistema externo.
Duração da vista e evidência de aceitação
AsyncPipe fornece uma subscrição gerida pela vista; o exemplo usa uma só binding para não criar pedidos duplicados por apresentação. A limpeza da subscrição quando a vista termina evita callbacks sobre um consumidor destruído, mas não é evidência de rollback remoto.
Para explicar o comportamento, segue escolha, subscrição, payload recebido, validação, estado emitido e apresentação. O exemplo assume um endpoint e não fornece backend nem bootstrap. A avaliação pede interpretar estas fronteiras e escolher decisões, sem instalar serviços ou executar os excertos.
// Reading example: assumes a read-only /api/orders/:id endpoint returning {total: number}.
// Angular 22 and RxJS 7-compatible operators; no backend or bootstrap is supplied here.
import {AsyncPipe} from '@angular/common';
import {HttpClient} from '@angular/common/http';
import {Component, inject} from '@angular/core';
import {Subject, catchError, map, of, switchMap} from 'rxjs';
type LookupState = {kind: 'idle' | 'ready' | 'error'; label: string};
function acceptTotal(data: unknown): number {
if (typeof data !== 'object' || data === null) throw new Error('Invalid order');
const total = (data as {total?: unknown}).total;
if (typeof total !== 'number' || !Number.isFinite(total)) throw new Error('Invalid total');
return total;
}
@Component({
selector: 'order-lookup', standalone: true, imports: [AsyncPipe],
template: `<label>Order ID <input #key></label>
<button type="button" (click)="choose(key.value)">Look up</button>
@if (state$ | async; as state) { <p>{{ state.label }}</p> }`,
})
export class OrderLookup {
private readonly http = inject(HttpClient);
private readonly choices = new Subject<string>();
readonly state$ = this.choices.pipe(switchMap(id => {
if (!id) return of<LookupState>({kind: 'idle', label: 'Choose an order'});
return this.http.get<unknown>('/api/orders/' + encodeURIComponent(id)).pipe(
map((data): LookupState => ({kind: 'ready', label: id + ': ' + acceptTotal(data).toFixed(2)})),
catchError(() => of<LookupState>({kind: 'error', label: 'Order could not be accepted'})),
);
}));
choose(id: string) { this.choices.next(id.trim()); }
}Uma única binding AsyncPipe subscreve state$. Cada escolha substitui a subscrição interna; uma escolha vazia produz estado idle. A fronteira aceita apenas total numérico finito e converte falhas de contrato ou de pedido numa mensagem explícita. catchError está dentro do pedido, permitindo escolhas posteriores.
Durante um pedido novo, a mensagem anterior pode permanecer até chegar outro estado; o exemplo não implementa um indicador de carregamento.
Armadilhas comuns
Assumir que get envia antes de subscribe; subscrever duas vezes sem perceber a repetição; confiar no genérico como schema; ignorar o retorno de HttpParams.set; colocar catchError fora do fluxo que se pretende recuperar; usar cancelamento como prova de rollback.
Tópicos relacionados: Formulários, validação e intenção do utilizador · Ciclo de vida, efeitos e limpeza reativa · Fronteiras de segurança e conteúdo confiável
Um pedido tem uma identidade, uma subscrição, um contrato de dados e uma decisão de aceitação. Mantém essas responsabilidades visíveis. Cancelar limita trabalho local em curso; repetir pode criar outro pedido; aceitar uma resposta exige mais do que um tipo declarado.
Referência: Current HTTP configuration · Angular 22; standalone components