Capítulo 11: Eloquent API Resources e Serialização de Dados REST
Especialização em Backend com PHP & Laravel • Laravel 11 & PHP 8.3+ • Eloquent ORM, Sanctum, Filas, Horizon e APIs Corporativas
🗺️ Mapa Conceitual do Tópico
flowchart TD
A["Cliente HTTP / Frontend"] --> B["API Gateway / Router"]
B --> C["Controller / Handler"]
C --> D["Service Layer (Regras de Negócio)"]
D --> E["Repository / ORM (Persistência)"]
E --> F["Banco de Dados / Cache"]
subgraph ARQ["Arquitetura do Capítulo"]
G["Conceito: Eloquent API Resources e Serialização de Dados REST"]
H["Segurança, Validação e Resiliência"]
I["Alta Performance e Escalabilidade"]
end
D --> ARQ
style A fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
style B fill:#fff3e0,stroke:#ff9800,stroke-width:2px
style C fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style D fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
style E fill:#fce4ec,stroke:#e91e63,stroke-width:2px
style F fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px
🏛️ 1. O Problema: Vazar o Model Direto na Resposta
Devolver um model Eloquent direto num return $produto; funciona porque o Laravel serializa via toArray()/toJson() — mas isso vaza toda coluna da tabela (incluindo password, timestamps internos, chaves estrangeiras cruas) e acopla o contrato da API à estrutura exata do banco: renomear uma coluna quebra todo cliente da API. API Resources resolvem isso com uma camada explícita de tradução entre o model e o JSON público.
<?php
// app/Http/Resources/ProdutoResource.php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class ProdutoResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'nome' => $this->nome,
'preco_formatado' => 'R$ ' . number_format($this->preco, 2, ',', '.'),
'criado_em' => $this->created_at->toISOString(),
// sku, custo_interno, deleted_at etc. NUNCA aparecem -- so o que for listado aqui
];
}
}
No controller: return new ProdutoResource($produto); para um único item, ou ProdutoResource::collection($produtos) para uma lista — o resource sabe se adaptar a ambos os casos.
🗂️ 2. ResourceCollection e o Envelope data
Quando o resultado é uma coleção paginada, ProdutoResource::collection() já envolve automaticamente a resposta num envelope {"data": [...]}. Para customizar esse envelope (adicionar metadados como total de registros, links de paginação, ou um bloco meta próprio), usa-se uma ResourceCollection dedicada:
<?php
// app/Http/Resources/ProdutoCollection.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ProdutoCollection extends ResourceCollection
{
public function toArray($request): array
{
return [
'data' => $this->collection,
'meta' => [
'total' => $this->collection->count(),
'gerado_em' => now()->toISOString(),
],
];
}
}
🔀 3. Campos Condicionais: whenLoaded, when e mergeWhen
Um erro comum é acessar uma relação ($this->categoria->nome) que não foi carregada via with() — isso dispara uma query N+1 silenciosa por trás do resource. whenLoaded() só inclui o campo se a relação já veio carregada, sem forçar uma nova consulta:
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'nome' => $this->nome,
'categoria' => new CategoriaResource($this->whenLoaded('categoria')),
// só aparece no JSON se o usuário autenticado for admin:
'custo_interno' => $this->when($request->user()?->is_admin, $this->custo_interno),
];
}
Isso torna o Resource também uma camada de autorização de campo: a mesma entidade pode expor mais ou menos dados dependendo de quem está pedindo, sem duplicar a classe.
🔗 Recursos Pedagógicos do Capítulo 11
| Recurso Didático | Finalidade | Link de Acesso |
|---|---|---|
| 📊 Slides de Aula | Apresentação visual interativa com Dark Mode e suporte a teclado | Ver Slides |
| 🧠 Quiz Formativo | Teste interativo de fixação com feedback imediato por alternativa | Fazer Quiz |
| 💻 Exemplos de Código | Demonstrações funcionais com código executável | Ver Exemplos |
| 🧩 Exercícios em 4 Níveis | Lista progressiva de fixação com gabarito em bloco colapsável | Resolver Exercícios |
| ⬅️ Capítulo Anterior | 📚 Sumário de Tópicos | Próximo Capítulo ➡️ |