JavaScript/Angular/Serviços e Injeção de Dependência
JavaScript⏱ ~2 min de leitura

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.

Exemplo.java
// ── 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),
    });
  }
}
💡 Dica pro

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.

Recompensa+40 XP+exercícios