Serviços e Injeção de Dependência
@Injectable e o padrão DI do Angular
Serviços (Services) em Angular são classes que centralizam lógica de negócio, acesso a dados e estado compartilhado. Enquanto componentes gerenciam a view, serviços cuidam da lógica. Essa separação segue o Single Responsibility Principle e torna o código mais testável.
O decorator @Injectable marca a classe para participar do sistema de Injeção de Dependência (DI). Com providedIn: "root", o Angular cria uma única instância do serviço para toda a aplicação (singleton) e a gerencia no DI container global. Os componentes declaram a dependência no constructor — o Angular a injeta automaticamente.
HttpClient, também um serviço, é a forma padrão de fazer chamadas HTTP. Retorna Observables (RxJS), não Promises — são mais poderosos: cancináveis, compostos com operators como pipe(), map(), catchError(). Mas você pode converter com firstValueFrom() para usar com async/await.
// ── Serviço: src/app/services/produto.service.ts ─
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, catchError, map, throwError } from 'rxjs';
export interface Produto {
id: number;
nome: string;
preco: number;
}
@Injectable({ providedIn: 'root' })
export class ProdutoService {
private readonly apiUrl = 'https://api.exemplo.com/produtos';
constructor(private http: HttpClient) {} // DI: HttpClient injetado
buscarTodos(): Observable<Produto[]> {
return this.http.get<Produto[]>(this.apiUrl).pipe(
catchError(erro => throwError(() => new Error('Falha ao buscar')))
);
}
buscarPorId(id: number): Observable<Produto> {
return this.http.get<Produto>(`${this.apiUrl}/${id}`);
}
criar(produto: Omit<Produto, 'id'>): Observable<Produto> {
return this.http.post<Produto>(this.apiUrl, produto);
}
}
// ── Componente: injeta e usa o serviço ─────────────
@Component({ selector: 'app-lista', template: `
<ul>
<li *ngFor="let p of produtos">{{ p.nome }} — {{ p.preco }}</li>
</ul>
` })
export class ListaComponent implements OnInit {
produtos: Produto[] = [];
constructor(private produtoService: ProdutoService) {} // injeção
ngOnInit(): void {
this.produtoService.buscarTodos().subscribe({
next: (dados) => (this.produtos = dados),
error: (err) => console.error(err),
});
}
}Sempre cancele assinaturas de Observables no ngOnDestroy para evitar memory leaks. Use takeUntilDestroyed() (Angular 16+), async pipe no template (cancela automaticamente), ou o padrão Subject/takeUntil.