Sari la conținut
← Construiește un REST API cu Laravel
Progres curs 0 / 7 lecții (0%)

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

Ț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 →

Folosim cookie-uri esențiale pentru funcționarea site-ului și, cu acordul tău, cookie-uri de analiză și publicitate. Partenerii noștri, inclusiv Google, pot folosi cookie-uri pentru a afișa reclame relevante. Detalii în Politica de cookie-uri.