Merhaba arkadaşlar, bugün Laravel ile API geliştirirken başımı çok ağrıtan bir konudan bahsedeceğim. Client tarafından gelen isteklerde hep aynı sorun vardı: "Abi bu API'den dönen verinin formatı çok karışık, bizim frontend'ci kafayı yedi!" veya "Bu alanı göstermememiz lazım, gizli bilgi!" diye feryatlar... İşte tam bu noktada, Laravel'in API Resources özelliği imdadıma yetişti. Eğer siz de response'larınızı tamamen kontrol etmek, farklı endpoint'ler için farklı veri yapıları döndürmek istiyorsanız, bu yazı tam size göre.
Neden Standart Model Dönmek Yetmiyor?
Eloquent modelini direkt `return` etmek çok kolay, biliyorum. Ama bir `User` modeliniz olduğunu düşünün. Kullanıcı listesi endpoint'inde sadece `id`, `name` ve `email` dönmek isterken, kullanıcı detay endpoint'inde `created_at`, `profile_picture` gibi ekstra alanlar da dönmek isteyebilirsiniz. Hatta belki de `password_hash` veya `email_verified_at` gibi alanları hiçbir zaman response'ta göstermek istemezsiniz. İşte API Resource'lar tam da bu kontrolü sağlıyor.
İlk API Resource'umuzu Oluşturalım
Terminalden basit bir Artisan komutu ile başlıyoruz. Diyelim ki bir `Product` modelimiz var ve bunun için özel bir resource oluşturacağız.
Bu komut, `app/Http/Resources` klasörü altında `ProductResource.php` dosyasını oluşturacak. Gelin bu dosyanın içine bakalım.
Şu an `parent::toArray($request)` çağrısı, modelin tüm özelliklerini olduğu gibi döndürüyor. Bizim sihirli metodumuz burası: toArray. Bu metodun içinde, response'ta görünmesini istediğimiz her şeyi manuel olarak tanımlayacağız.
Response Formatını Özelleştirme
Şimdi, `Product` modelimizin alanlarını kontrol altına alalım. Diyelim ki `id`, `name`, `slug`, `price` ve `stock` alanlarını göstermek istiyoruz. Ayrıca `created_at` alanını da bir tarih formatına çevirip eklemek istiyoruz.
Gördüğünüz gibi, sadece istediğim alanları döndürdüm. Hatta `name` alanını frontend'deki ihtiyaca göre `productName` olarak yeniden adlandırdım. `price` alanını da kendi içinde bir obje yapısına dönüştürdüm. `stock` değerini boolean bir `inStock` değerine çevirdim. Bu kadar esneklik harika değil mi?
İlişkileri Dahil Etmek
Peki ya ürünün bir kategorisi (`Category` modeli) varsa ve onu da response'a eklemek istiyorsak? Çok kolay! Diyelim ki `Product` modelinde bir `category()` ilişkisi tanımlı. Aynı şekilde bir `CategoryResource` da oluşturduğumuzu varsayalım.
Buradaki whenLoaded metodunun güzelliği, eğer kategori ilişkisi query'de `with('category')` ile yüklenmişse sadece o zaman response'a dahil etmesi. Bu, gereksiz query'lerin önüne geçiyor.
Controller'da Kullanımı
Resource'u hazırladık, şimdi sıra onu Controller'da kullanmaya geldi. Tek bir ürün veya koleksiyon (liste) döndürürken nasıl kullanacağımızı görelim.
`ProductResource::collection()` metodu sayesinde, paginate edilmiş bir koleksiyonu bile sorunsuz bir şekilde dönüştürebiliyoruz. Response, `data` anahtarının içinde resource'dan gelen formatla, `links` ve `meta` anahtarlarıyla birlikte düzgünce geliyor.
İşte benim Laravel API'lerimde veri formatını tamamen kontrol altına almamı sağlayan en temiz çözüm bu oldu. Artık frontend ekip arkadaşlarım bana küsmüyor!
Peki siz Laravel'de API response'larınızı nasıl şekillendiriyorsunuz? Hiç `API Resources` kullanmadan önce başınıza format karmaşasından dolayı komik olaylar geldi mi? Ya da koleksiyonları dönüştürürken farklı bir püf noktanız var mı? Yorumlarda paylaşalım!
Eloquent modelini direkt `return` etmek çok kolay, biliyorum. Ama bir `User` modeliniz olduğunu düşünün. Kullanıcı listesi endpoint'inde sadece `id`, `name` ve `email` dönmek isterken, kullanıcı detay endpoint'inde `created_at`, `profile_picture` gibi ekstra alanlar da dönmek isteyebilirsiniz. Hatta belki de `password_hash` veya `email_verified_at` gibi alanları hiçbir zaman response'ta göstermek istemezsiniz. İşte API Resource'lar tam da bu kontrolü sağlıyor.
Terminalden basit bir Artisan komutu ile başlıyoruz. Diyelim ki bir `Product` modelimiz var ve bunun için özel bir resource oluşturacağız.
Bash:
php artisan make:resource ProductResource
Bu komut, `app/Http/Resources` klasörü altında `ProductResource.php` dosyasını oluşturacak. Gelin bu dosyanın içine bakalım.
PHP:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
/
Transform the resource into an array.
@param \Illuminate\Http\Request $request
@return array
/
public function toArray($request)
{
return parent::toArray($request);
}
}
Şu an `parent::toArray($request)` çağrısı, modelin tüm özelliklerini olduğu gibi döndürüyor. Bizim sihirli metodumuz burası: toArray. Bu metodun içinde, response'ta görünmesini istediğimiz her şeyi manuel olarak tanımlayacağız.
Şimdi, `Product` modelimizin alanlarını kontrol altına alalım. Diyelim ki `id`, `name`, `slug`, `price` ve `stock` alanlarını göstermek istiyoruz. Ayrıca `created_at` alanını da bir tarih formatına çevirip eklemek istiyoruz.
PHP:
public function toArray($request)
{
return [
'id' => $this->id,
'productName' => $this->name,
'productSlug' => $this->slug,
'price' => [
'amount' => $this->price,
'currency' => 'TRY'
],
'inStock' => $this->stock > 0,
'listedAt' => $this->created_at->format('d.m.Y H:i'),
];
}
Gördüğünüz gibi, sadece istediğim alanları döndürdüm. Hatta `name` alanını frontend'deki ihtiyaca göre `productName` olarak yeniden adlandırdım. `price` alanını da kendi içinde bir obje yapısına dönüştürdüm. `stock` değerini boolean bir `inStock` değerine çevirdim. Bu kadar esneklik harika değil mi?
Peki ya ürünün bir kategorisi (`Category` modeli) varsa ve onu da response'a eklemek istiyorsak? Çok kolay! Diyelim ki `Product` modelinde bir `category()` ilişkisi tanımlı. Aynı şekilde bir `CategoryResource` da oluşturduğumuzu varsayalım.
PHP:
public function toArray($request)
{
return [
'id' => $this->id,
'productName' => $this->name,
// ... diğer alanlar
'category' => new CategoryResource($this->whenLoaded('category')),
];
}
Buradaki whenLoaded metodunun güzelliği, eğer kategori ilişkisi query'de `with('category')` ile yüklenmişse sadece o zaman response'a dahil etmesi. Bu, gereksiz query'lerin önüne geçiyor.
Resource'u hazırladık, şimdi sıra onu Controller'da kullanmaya geldi. Tek bir ürün veya koleksiyon (liste) döndürürken nasıl kullanacağımızı görelim.
PHP:
use App\Http\Resources\ProductResource;
use App\Models\Product;
// Tek bir kaynak döndürme (Show)
public function show($id)
{
$product = Product::with('category')->findOrFail($id);
return new ProductResource($product);
}
// Koleksiyon döndürme (Index)
public function index()
{
$products = Product::with('category')->paginate(20);
return ProductResource::collection($products);
}
`ProductResource::collection()` metodu sayesinde, paginate edilmiş bir koleksiyonu bile sorunsuz bir şekilde dönüştürebiliyoruz. Response, `data` anahtarının içinde resource'dan gelen formatla, `links` ve `meta` anahtarlarıyla birlikte düzgünce geliyor.
İşte benim Laravel API'lerimde veri formatını tamamen kontrol altına almamı sağlayan en temiz çözüm bu oldu. Artık frontend ekip arkadaşlarım bana küsmüyor!
Peki siz Laravel'de API response'larınızı nasıl şekillendiriyorsunuz? Hiç `API Resources` kullanmadan önce başınıza format karmaşasından dolayı komik olaylar geldi mi? Ya da koleksiyonları dönüştürürken farklı bir püf noktanız var mı? Yorumlarda paylaşalım!