Rute, controllere, API Resources
Lectură estimată: 3 minute
Estimare pentru text, la un ritm de 180 de cuvinte pe minut. Timpul pentru analizarea codului, exerciții și proiecte se adaugă separat și depinde de ritmul tău.
În Laravel, rutele de API stau în `routes/api.php` (prefixate automat cu `/api`). Controllerele de API întorc date, nu vederi. API Resources transformă modelele Eloquent în structura JSON exactă pe care vrei s-o expui — un strat de traducere între baza de date și API.
Rute de API
// routes/api.php
Route::prefix("v1")->group(function () {
Route::apiResource("articole", ArticolController::class);
// GET/POST /api/v1/articole, GET/PUT/DELETE /api/v1/articole/{articol}
});Controller de API
class ArticolController extends Controller
{
public function index()
{
return ArticolResource::collection(
Articol::with("autor")->latest()->paginate(15)
);
}
public function store(ArticolRequest $request)
{
$articol = Articol::create($request->validated());
return (new ArticolResource($articol))
->response()
->setStatusCode(201);
}
public function show(Articol $articol)
{
return new ArticolResource($articol->load("autor"));
}
public function destroy(Articol $articol)
{
$articol->delete();
return response()->noContent(); // 204
}
}API Resource
class ArticolResource extends JsonResource
{
public function toArray($request): array
{
return [
"id" => $this->id,
"titlu" => $this->titlu,
"slug" => $this->slug,
"continut" => $this->continut,
"publicat_la" => $this->publicat_la?->toIso8601String(),
"autor" => new UtilizatorResource($this->whenLoaded("autor")),
];
}
}De ce Resources
- Controlezi exact ce câmpuri expui (nu scapi accidental parole, note interne).
- Formatezi consecvent (date ISO 8601, numere ca numere).
- whenLoaded() include relații doar dacă au fost eager-loaded — fără N+1.
- Schimbi structura API fără să atingi modelele.
Includerea condiționată
return [ "id" => $this->id, "titlu" => $this->titlu, // doar pentru admin: "note_interne" => $this->when($request->user()?->isAdmin(), $this->note_interne), // doar dacă relația e încărcată: "comentarii" => ComentariuResource::collection($this->whenLoaded("comentarii")), ];
Exercițiu
Construiește un apiResource complet pentru articole: rute în api.php sub /v1, controller care întoarce Resources, un ArticolResource care expune doar câmpurile publice și include autorul cu whenLoaded. Testează cu un client HTTP (Postman, curl, sau .http în editor).
Greșeli frecvente
- Întorci direct modelul Eloquent (expui toate coloanele, inclusiv cele sensibile).
- Uiți ->response()->setStatusCode(201) la creare și întorci 200.
- Incluzi relații fără whenLoaded și reintroduci N+1.
- Pui logică de business în Resource (e doar transformare de date).
De reținut
- routes/api.php + apiResource() pentru CRUD REST.
- Controllerele de API întorc Resources, nu vederi.
- Resource = strat de traducere model → JSON, cu câmpuri controlate.
- whenLoaded() și when() pentru includere condiționată.
Pe scurt
apiResource + JsonResource îți dau un API curat: rute convenționale, răspunsuri controlate, fără scurgeri de date și fără N+1.
API Resource cu listă explicită de câmpuri
Resource-ul controlează reprezentarea publică a modelului. Nu întoarce automat toate coloanele, fiindcă schema poate primi ulterior câmpuri sensibile. Păstrează relațiile condiționate de încărcare pentru a evita interogări ascunse. Controllerul autorizează și pregătește datele, iar resource-ul le transformă. Forma răspunsului trebuie verificată printr-un test care caută atât câmpurile prezente, cât și pe cele interzise.
Exemplu de lucru
public function toArray(Request $request): array {
return [
'id' => $this->id,
'service' => $this->service,
'status' => $this->status,
'created_at' => $this->created_at?->toISOString(),
];
}
Controller: return new ServiceRequestResource($serviceRequest);
Nu include: note interne, tokenuri, email fără necesitate.Interpretarea rezultatului
Adăugarea unei coloane în DB nu trebuie să schimbe accidental contractul API. Testează resource-ul cu un model care are note interne și confirmă că nu apar. Null pentru o dată absentă este o decizie de contract care trebuie păstrată consecvent.
Exercițiu de consolidare
Adaugă un câmp public nou într-o versiune compatibilă și descrie ce client ar putea fi afectat dacă schimbi tipul unui câmp existent.
Aplicație practică
Sarcina
Returnează un serviciu prin API Resource.
Rezolvare orientativă și verificare
Expune doar id, titlu și slug; exclude câmpurile interne. Testează explicit că datele private nu apar.
Greșeală de evitat
Serializarea întregului model poate divulga coloane noi.
Documentație și surse
- Documentația Laravel 11 — versiunea aplicației demonstrative — Laravel
- OWASP Top 10 — OWASP
Ți-a plăcut lecția? Continuă cursul complet
Ai citit o lecție gratuită. Celelalte lecții, aplicațiile practice și materialele se deblochează odată cu cursul.
199 lei
Plată unică, acces pe viață la toate cele 7 lecții.
Vezi ce conține cursul →