Kaan Tanış, Mersin’de freelance web tasarım, yazılım geliştirme ve mobil uygulama üreten full-stack geliştirici ve UI tasarımcısıdır.

Controller'ınız Şişmanlamış Olabilir: Laravel'de API'yi Zayıflatmanın İki Yolu (önerilen)

Controller'ınız Şişmanlamış Olabilir: Laravel'de API'yi Zayıflatmanın İki Yolu (önerilen)

Mobil uygulamaya API yazarken sahne genelde aynı ilerliyor. İlk endpoint temiz çıkıyor. Üçüncüde validation satırları controller'ı doldurmaya başlıyor. Beşincide her endpoint farklı şekilde JSON dönüyor. Biri veriyi data altında veriyor, biri düz veriyor, biri hata mesajını bambaşka formatta basıyor. Uygulama tarafı her cevaba ayrı parser yazmak zorunda kalıyor.

Sorun genelde bilgi eksikliği değil, erteleme. "Şu endpoint'i çıkarayım, toparlamayı sonra yaparım" cümlesi birikiyor. İki alışkanlık bu dağınıklığı baştan kesiyor: validation için Form Request, cevap şekli için API Resource.

Validation controller'da birikmesin

Tipik bir store metodu şöyle görünüyor:

public function store(Request $request)
{
    $request->validate([
        'name' => 'required|string|max:255',
        'price' => 'required|numeric|min:0',
        'stock' => 'nullable|integer|min:0',
    ]);

    // ... kayıt işlemi
}

Tek endpoint varken sorun yok. Ama kural sayısı artınca, update metodu eklenince, bir de "taslak kaydederken fiyat zorunlu olmasın" gibi istisna gelince bu blok şişiyor. Controller'ın işi istek karşılayıp cevap dönmek, kural listesi tutmak değil.

Form Request validation'ı kendi sınıfına taşıyor:

php artisan make:request StoreProductRequest
class StoreProductRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'name' => 'required|string|max:255',
            'price' => 'required|numeric|min:0',
            'stock' => 'nullable|integer|min:0',
        ];
    }
}

Controller tarafı iki satıra iniyor:

public function store(StoreProductRequest $request)
{
    $data = $request->validated();

    // ... kayıt işlemi
}

Burada güzel olan detay şu: metoda gelen istek zaten doğrulanmış oluyor. validated() sadece geçen alanları veriyor, fazladan gönderilen anahtarları eliyor. Kural değişince controller'a dokunmuyorsunuz, tek dosya değişiyor. Update için ayrı kurallar gerekiyorsa UpdateProductRequest açıyorsunuz, iki metodun kuralları birbirine bulaşmıyor.

Küçük bir not: authorize() metodu ilk bakışta gereksiz görünüyor. Herkes giriş yapabiliyorsa true dönüp geçiyorsunuz. Ama "sadece satıcı ürün ekleyebilir" gibi bir kural geldiğinde yeri hazır. Yetki kontrolünü metoda gömmek yerine oraya yazmak, altı ay sonra bakınca nerede olduğunu hatırladığınız tek yer oluyor.

Cevap şekli her endpoint'te aynı olsun

İkinci dağınıklık response tarafında. Modeli olduğu gibi döndürmek ilk gün pratik geliyor:

return response()->json($product);

Sonra gizli kalması gereken bir alan sızıyor, tarih formatı uygulamayı bozuyor, ilişki verisi bir endpoint'te var birinde yok. Çözüm API Resource, yani model ile JSON arasına koyduğunuz ince bir katman:

php artisan make:resource ProductResource
class ProductResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'price' => (float) $this->price,
            'in_stock' => $this->stock > 0,
            'created_at' => $this->created_at->toDateTimeString(),
        ];
    }
}

Kullanımı tek satır:

return new ProductResource($product);

// Liste için:
return ProductResource::collection($products);

Bunun karşılığını ilk değişiklikte alıyorsunuz. Fiyat formatı değişecekse, bir alan kalkacaksa, tarihler başka formata geçecekse tek dosya değişiyor. On endpoint aynı anda düzeliyor. Uygulama tarafı da rahatlıyor çünkü her cevap aynı iskeletle geliyor.

Hata cevaplarını da standarda bağlayın

Validation hatasında Laravel, istek JSON bekliyorsa zaten 422 dönüyor ve hangi alanın neden geçemediğini söylüyor. Ekstra iş yapmanıza gerek yok. Dikkat edilecek nokta küçük: mobil tarafın Accept: application/json başlığını göndermesi lazım. O başlık yoksa Laravel hata durumunda JSON yerine yönlendirme dönüyor ve uygulama tarafı anlamsız bir cevapla baş başa kalıyor. Bu, kodda değil istemcide çözülen bir satır ama unutulunca saat yaktırıyor.

Kayıt başarılıysa 201, silme sonrası içerik yoksa 204 dönmek gibi detaylar da aynı dosyalarda duruyor. Resource ve Request yapısı oturunca bu kararları her metoda ayrı ayrı yazmıyorsunuz.

Her projede gerekir mi

Açık konuşayım: tek sayfalık bir formun arkası için Form Request açmak bazen fazla. İki alanlı bir iletişim formuysa controller içindeki kısa validate yeterli. Resource tarafı da öyle. Admin paneline iki liste basan bir iç araçta modele dokunmadan düz döndürmek sorun çıkarmaz.

Çizgi şurada: aynı veri birden fazla yerden dönüyorsa, hele bir de mobil uygulama tüketiyorsa, bu iki katman kendini ilk haftadan ödüyor. Tek tük endpoint varsa getirmeyin, kalabalıklaşınca taşıyın. Erken soyutlama ile geç kalmış temizlik arasında ince bir çizgi var, kararı endpoint sayısına göre verin.

Kontrol listesi

  • Validation controller'da 5 satırı geçtiyse Form Request'e taşıyın.

  • Modeli çıplak döndürmeyi bırakın, dışarıya giden şekli Resource belirlesin.

  • Hata formatını test edin: 422 cevabı her endpoint'te aynı iskelette mi geliyor, bakın.

  • Mobil tarafın JSON başlığını gönderdiğini doğrulayın, yoksa hata cevapları şaşırır.

  • Tek endpoint'lik işlerde katman açmayın, kalabalıklaşınca taşıyın.

API tarafındaki dağınıklık genelde büyük mimari hatalardan çıkmıyor. Küçük ertelemelerin birikmesinden çıkıyor. İki dosya tipi, düzenli kullanıldığında o birikmeyi durduruyor.

İlgili Yazılar

Yorum Yap

Yorumunuz onaylandıktan sonra yayınlanacaktır. Bildirim almak isterseniz e-posta adresinizi girebilirsiniz.