Modern web ve mobil uygulamaların kalbi REST API'lerdir. Frontend'i React, Vue veya Next.js ile yapsanız, mobil uygulamayı React Native veya Flutter'la geliştirseniz — backend'iniz neredeyse her zaman bir API olarak konumlanıyor. Laravel 11, API geliştirme için en güçlü PHP framework'lerinden biri. Eloquent ORM'in gücü, Sanctum'un sadeliği, queue sistemi, broadcasting, scheduling — kurumsal düzeyde API'lar için ihtiyacınız olan her şey hazır geliyor.
Bu kapsamlı rehberde sıfırdan production'a kadar tüm adımları detaylı şekilde işleyeceğiz: proje kurulumu, veritabanı tasarımı, authentication, rate limiting, validation, error handling, versiyonlama, test, dokümantasyon ve deploy. Junior'dan senior'a tüm seviyelerdeki PHP geliştiricileri için faydalı olacak.
1. Proje Kurulumu ve İlk Yapılandırma
Composer ile Laravel Yükleme
composer create-project laravel/laravel my-api
cd my-api
php artisan install:api
Laravel 11'de install:api komutu, Sanctum authentication ve API route'larını otomatik kurar. Bu komut routes/api.php dosyasını oluşturur ve gerekli middleware'leri yapılandırır.
Önemli Konfigürasyon Adımları
# .env dosyasını yapılandır
APP_NAME="MyAPI"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost:8000
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=my_api
DB_USERNAME=root
DB_PASSWORD=
# Cache ve queue için Redis
CACHE_STORE=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
Geliştirme Ortamı için Docker
Laravel Sail ile tek komutla Docker ortamı kurabilirsiniz:
php artisan sail:install
./vendor/bin/sail up -d
Sail; PHP 8.3, MySQL 8, Redis, Mailpit, MinIO ve daha fazlasını otomatik konteynerleştirir.
2. Veritabanı Tasarımı ve Migration'lar
Migration Yazma
php artisan make:model Product -mfsc
Bu komut model, migration, factory, seeder ve controller'ı bir arada üretir. Migration dosyasını düzenleyelim:
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('sku')->unique();
$table->string('name');
$table->text('description')->nullable();
$table->decimal('price', 10, 2);
$table->integer('stock')->default(0);
$table->foreignId('category_id')->constrained();
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->softDeletes();
$table->index(['is_active', 'category_id']);
});
İlişkiler ve Eloquent Modeller
class Product extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = ['sku', 'name', 'description', 'price', 'stock', 'category_id', 'is_active'];
protected $casts = [
'price' => 'decimal:2',
'is_active' => 'boolean',
];
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
public function reviews(): HasMany
{
return $this->hasMany(Review::class);
}
public function scopeActive($query)
{
return $query->where('is_active', true);
}
}
3. API Resource'lar (Veri Dönüşümü)
Modeller doğrudan JSON'a dönüştürülmemeli. Resource sınıfları kullanın — bu sayede database alanlarını doğrudan dışa açmaz, response yapısını kontrol edersiniz.
php artisan make:resource ProductResource
class ProductResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'sku' => $this->sku,
'name' => $this->name,
'description' => $this->description,
'price' => [
'amount' => $this->price,
'currency' => 'TRY',
'formatted' => number_format($this->price, 2) . ' TL',
],
'stock' => $this->stock,
'is_in_stock' => $this->stock > 0,
'category' => new CategoryResource($this->whenLoaded('category')),
'created_at' => $this->created_at->toIso8601String(),
];
}
}
Resource Collection'lar
Çoklu kayıt döndürmek için resource collection kullanın. Pagination meta verisi otomatik eklenir:
public function index(Request $request): ResourceCollection
{
$products = Product::active()
->with('category')
->paginate($request->per_page ?? 20);
return ProductResource::collection($products);
}
4. Authentication: Sanctum vs JWT
Laravel Sanctum (Önerilen)
Token bazlı kimlik doğrulama için Sanctum yeterli. JWT karmaşıklığına ihtiyaç yok; özellikle SPA ve mobil uygulamalarınız için ideal.
// Login endpoint
public function login(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['Geçersiz kimlik bilgileri.'],
]);
}
$token = $user->createToken('mobile-app', ['product:read', 'order:write'])->plainTextToken;
return response()->json([
'token' => $token,
'user' => new UserResource($user),
]);
}
Token Yetenekleri (Abilities)
Sanctum, token bazında scope/yetenek tanımlamayı destekler:
Route::get('/products', function () {
// Tüm authentication'lı kullanıcılar
})->middleware('auth:sanctum');
Route::post('/products', function () {
// Sadece product:write yeteneğine sahip token'lar
})->middleware(['auth:sanctum', 'ability:product:write']);
JWT Alternatifi
Mikroservis mimarisinde veya stateless ihtiyacınız varsa JWT tercih edilebilir. php-open-source-saver/jwt-auth paketi ile Laravel'e JWT eklenebilir. Ama çoğu durumda Sanctum yeterli ve sade.
5. Validation ve Form Request'ler
Inline validation kötü bir pratik. Form Request sınıfları ile validation logic'ini ayır:
php artisan make:request StoreProductRequest
class StoreProductRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->can('create', Product::class);
}
public function rules(): array
{
return [
'sku' => ['required', 'string', 'max:50', 'unique:products,sku'],
'name' => ['required', 'string', 'max:255'],
'price' => ['required', 'numeric', 'min:0'],
'stock' => ['required', 'integer', 'min:0'],
'category_id' => ['required', 'exists:categories,id'],
];
}
public function messages(): array
{
return [
'sku.unique' => 'Bu SKU kodu zaten kullanılıyor.',
'price.min' => 'Fiyat negatif olamaz.',
];
}
}
6. Rate Limiting (DDoS Koruması)
API'nizi DDoS'tan ve abuse'dan koruyun. routes/api.php içinde:
Route::middleware(['auth:sanctum', 'throttle:api'])->group(function () {
// 60 istek / dakika - varsayılan
});
// Özel rate limit
RateLimiter::for('api', function (Request $request) {
return $request->user()
? Limit::perMinute(60)->by($request->user()->id)
: Limit::perMinute(20)->by($request->ip());
});
// Login için sıkı rate limit (brute force koruması)
RateLimiter::for('login', function (Request $request) {
return Limit::perMinute(5)->by($request->ip())
->response(function () {
return response()->json(['error' => 'Çok fazla deneme'], 429);
});
});
7. API Versiyonlama
API'nizi /api/v1/, /api/v2/ gibi versiyonlayın. Eski client'lar bozulmadan yeni özellikler ekleyebilirsiniz.
// routes/api.php
Route::prefix('v1')->group(function () {
Route::apiResource('products', \App\Http\Controllers\Api\V1\ProductController::class);
});
Route::prefix('v2')->group(function () {
Route::apiResource('products', \App\Http\Controllers\Api\V2\ProductController::class);
});
Alternatif: Header-based versioning — Accept: application/vnd.api+json;version=2
8. Error Handling ve Standart Response Format
Tutarlı bir hata yapısı için custom exception handler:
// bootstrap/app.php (Laravel 11)
->withExceptions(function (Exceptions $exceptions) {
$exceptions->render(function (NotFoundHttpException $e, Request $request) {
if ($request->is('api/*')) {
return response()->json([
'message' => 'Kayıt bulunamadı',
'code' => 'NOT_FOUND',
], 404);
}
});
$exceptions->render(function (ValidationException $e, Request $request) {
return response()->json([
'message' => 'Validation failed',
'errors' => $e->errors(),
'code' => 'VALIDATION_ERROR',
], 422);
});
})
9. API Dokümantasyonu
Scribe ile Otomatik Dokümantasyon
composer require --dev knuckleswtf/scribe
php artisan scribe:install
php artisan scribe:generate
Scribe controller'larınızdaki PHPDoc yorumlarını okuyup güzel HTML/Postman/OpenAPI dokümantasyonu üretir.
L5-Swagger Alternatifi
OpenAPI standardına uygun dokümantasyon için darkaonline/l5-swagger kullanılabilir. Daha standart, daha çok client kütüphanesiyle uyumlu.
10. Test Yazma (PHPUnit)
Feature Test Örnekleri
class ProductApiTest extends TestCase
{
use RefreshDatabase;
public function test_kullanici_urun_listeleyebilir(): void
{
Product::factory()->count(15)->create();
$user = User::factory()->create();
$response = $this->actingAs($user, 'sanctum')
->getJson('/api/v1/products');
$response->assertOk()
->assertJsonStructure([
'data' => ['*' => ['id', 'sku', 'name', 'price']],
'meta' => ['current_page', 'total'],
]);
}
public function test_yetkisiz_kullanici_urun_olusturamaz(): void
{
$response = $this->postJson('/api/v1/products', [
'sku' => 'TEST-001',
'name' => 'Test Product',
'price' => 100,
'stock' => 10,
]);
$response->assertUnauthorized();
}
}
Test Coverage Hedefi
Profesyonel projelerde minimum % 80 test coverage hedeflenir. Kritik iş mantığı için % 100 hedeflenir.
11. Performans Optimizasyonu
N+1 Query Problemi
Eloquent'in en sık karşılaşılan tuzağı. Çözüm: eager loading.
// Kötü - N+1
$products = Product::all();
foreach ($products as $product) {
echo $product->category->name; // Her ürün için ayrı query
}
// İyi - Eager loading
$products = Product::with('category')->get();
Caching Stratejisi
$products = Cache::remember('products.list', 3600, function () {
return Product::active()->with('category')->get();
});
Database İndeksleme
Sıkça filtrelenen alanlara index ekleyin. EXPLAIN sorgu analiziyle yavaş query'leri tespit edin.
12. Production Deploy
Environment Yapılandırması
# .env.production
APP_ENV=production
APP_DEBUG=false
LOG_LEVEL=warning
# Cache hepsini production'da
php artisan config:cache
php artisan route:cache
php artisan view:cache
Queue Worker'lar
Mail, notification, heavy task'lar queue'ya alınmalı:
# Supervisor ile queue worker
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/api/artisan queue:work --queue=default --sleep=3 --tries=3
autostart=true
autorestart=true
numprocs=4
Nginx Konfigürasyonu
server {
listen 443 ssl http2;
server_name api.example.com;
root /var/www/api/public;
index index.php;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}
Hosting Seçenekleri
- Laravel Forge: DigitalOcean/AWS/Hetzner üzerinde tek tıkla deploy. Aylık 19$.
- Laravel Vapor: AWS Lambda üzerinde serverless deploy. Yüksek ölçek için ideal.
- Kendi VPS: Daha ucuz ama ekstra DevOps işi. Ubuntu + Nginx + PHP-FPM + MySQL/PostgreSQL.
- Türkiye sunucu: Hosting.com.tr, Veriteknik gibi yerli sağlayıcılarla yasal uyumluluk avantajı.
13. Monitoring ve Logging
Production'da göz açık olun:
- Sentry: Hata takibi, alert'leri
- Laravel Telescope: Local debugging için
- New Relic / Datadog: APM (Application Performance Monitoring)
- ELK Stack: Log aggregation
- Grafana + Prometheus: Metric görselleştirme
Sonuç: Laravel ile API Geliştirme Eğlencelidir
Laravel ile REST API geliştirmek hızlı, güvenli ve eğlenceli. Bu rehberdeki adımları takip ederek production-ready bir API geliştirebilirsiniz. Profesyonel API ihtiyacınız mı var? EMIXHAS Yazılım ile iletişime geçin. Özel yazılım hizmetlerimiz kapsamında Laravel REST API geliştirme, mevcut API'larınızın audit'i ve performans optimizasyonu yapıyoruz.