Teknoloji

Laravel’de Merkezi Hata Yönetimi ve Standart API Response Yapısı

📅 Jan 31, 2026
Modern bir API geliştirirken en büyük problemlerden biri, tutarsız hata mesajları, dağınık try/catch blokları ve her endpoint’te farklı response formatlarıdır. Bu yazıda, Laravel projelerinde bu problemleri kökten çözen merkezi exception yönetimi ve standart API response yapısını ele alıyorum.

Geliştirdiğimiz Handler sınıfı sayesinde;

  • Authentication, authorization, validation ve HTTP hataları tek bir noktadan yakalanır
  • API istemcilerine anlamlı, tutarlı ve okunabilir JSON cevaplar döndürülür
  • Debug moduna göre güvenli hata detayları kontrol edilir
  • Özel exception’lar (BaseException) ile iş kurallarına özel hatalar yönetilir

Bunun yanında ApiResponse helper sınıfı ile;

  • Başarılı ve hatalı tüm cevaplar aynı formatta döner
  • HTTP status code’lar doğru ve standart şekilde kullanılır
  • Resource ve collection response’ları ekstra kod yazmadan yönetilir
  • Frontend ve mobil uygulamalar için öngörülebilir bir API sözleşmesi sağlanır

Bu yaklaşım sayesinde API katmanı daha temiz, bakımı kolay ve ölçeklenebilir hale gelir.
Yeni endpoint eklerken response formatını düşünmek yerine, iş mantığına odaklanmak yeterli olur.

🎯 Kısaca Ne Kazandırır?

  • ✅ Tek merkezden hata yönetimi
  • ✅ Tutarlı API response formatı
  • ✅ Daha az tekrar eden kod
  • ✅ Frontend ile net bir sözleşme
  • ✅ Debug & production ayrımı
  • ✅ Kurumsal API mimarisi
                             // ===== Handler =====
<?php

namespace App\Exceptions;

use App\Enums\ErrorMessages;
use App\Support\Helpers\ApiResponse;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;

/**
* Bu sınıf api isteklerinde oluşabilecek hataları yakalayabilmemiz için yazdığımız exception handler sınıfı
*/
class Handler
{
public static function handle(Request $request, Throwable $exception)
{
return match (true) {
$exception instanceof AuthenticationException => ApiResponse::error(ErrorMessages::Unauthenticated->message(), 401),

$exception instanceof AuthorizationException => ApiResponse::error(ErrorMessages::Unauthorized->message(), 403),

$exception instanceof AccessDeniedHttpException => ApiResponse::error(ErrorMessages::Unauthorized->message(), 403),

$exception instanceof BaseException => ApiResponse::error($exception->getMessage(), $exception->getCode()),

$exception instanceof MethodNotAllowedHttpException => ApiResponse::error(ErrorMessages::MethodNotAllowed->message(), 405),

$exception instanceof ModelNotFoundException => ApiResponse::error(ErrorMessages::ModelNotFound->message(), 404),

$exception instanceof NotFoundHttpException => ApiResponse::error(ErrorMessages::NotFound->message(), 404),

$exception instanceof ValidationException => ApiResponse::error($exception->getMessage(), 422, $exception->errors()),

default => ApiResponse::error(
config('app.debug') ? $exception->getMessage() : ErrorMessages::InternalServerError->message(),
500,
config('app.debug') ? $exception->getTrace() : null
),
};
}
}



// ===== ErrorMessages =====
<?php

namespace App\Enums;

/**
* Bu enum sınıfı api isteklerinde oluşabilecek hataları tanımlamak için kullanılır
*/
enum ErrorMessages: string
{
case TokenExpired = 'token_expired';
case EmailAlreadyVerified = 'email_already_verified';
case InvalidCredentials = 'invalid_credentials';
case Unauthenticated = 'unauthenticated';
case Unauthorized = 'unauthorized';
case MethodNotAllowed = 'method_not_allowed';
case ModelNotFound = 'model_not_found';
case NotFound = 'not_found';
case InternalServerError = 'internal_server_error';

public function message(): string
{
return __('errors.' . $this->value);
}
}


// ===== ApiResponse =====
<?php

namespace App\Support\Helpers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;

class ApiResponse
{
public static function success(array|JsonResource|null $data = null, ?string $message = null, int $statusCode = 200): JsonResponse
{
return response()->json([
'data' => $data,
'status' => true,
'status_code' => $statusCode,
'message' => $message ?? trans('apiresponse.success_message'),
], $statusCode);
}

public static function item(array|JsonResource|null $data = null, ?string $message = null, int $statusCode = 200)
{
return self::success($data, $message, $statusCode);
}

public static function error(?string $message = null, int $statusCode = 400, array $errors = []): JsonResponse
{
if ($errors === []) {
$errors = [$message];
}

return response()->json([
'status' => false,
'status_code' => $statusCode,
'message' => $message ?? trans('apiresponse.error_message'),
'errors' => $errors,
], $statusCode);
}

public static function created($data = null, ?string $message = null): JsonResponse
{
return self::item($data, $message ?? trans('apiresponse.created_message'), 201);
}

public static function updated($data = null, ?string $message = null): JsonResponse
{
return self::item($data, $message ?? trans('apiresponse.updated_message'));
}

public static function deleted(?string $message = null): JsonResponse
{
return self::item(null, $message ?? trans('apiresponse.deleted_message'));
}

public static function collection(ResourceCollection $collection, ?string $message = null): JsonResponse
{
$return = [
'status' => true,
'status_code' => 200,
'message' => $message ?? trans('apiresponse.success_message'),
'data' => $collection->response()->getData()->data,
];

if (!empty($collection->response()->getData()->meta)) {
$meta = $collection->response()->getData()->meta;
$return['meta'] = $meta;
unset($meta->links);
unset($meta->path);
}

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


// ===== NotificationController =====
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\Api\Notifications\NotificationResource;
use App\Support\Helpers\ApiResponse;
use Illuminate\Http\Request;
/**
* Örnek Kullanım
*/
class NotificationController extends Controller
{
public function index(Request $request)
{
$request->validate([
'per_page' => 'integer|nullable',
]);

return ApiResponse::collection(
NotificationResource::collection(
\Auth::user()->notifications()
->paginate($request->per_page ?? 10)
)
);
}

}
📌 Yazı Bilgileri
  • Hedef: API tarafında oluşabilecek tüm hataları tek merkezden, tutarlı ve okunabilir şekilde yönetmek
  • Amacı: Laravel projelerinde standart, anlaşılır ve frontend-dostu API response yapısı oluşturmak
  • Mimari: Merkezi Hata Yönetimi & Standart API Response Mimarisi
  • Debug Modu Desteği: Development ortamında detaylı hata mesajı ve stack trace
  • Exception Yönetimi: Custom Exception Handler (Merkezi Exception Yakalama)
  • Validation Hataları: 422 status code ile detaylı alan bazlı hata döndürme
  • API Response Katmanı: Custom ApiResponse Helper Sınıfı
  • Production Güvenliği: Canlı ortamda kullanıcıya sadece güvenli ve standart hata mesajları döndürme
  • Hata Yönetim Yaklaşımı: HTTP Status Code uyumlu, enum destekli hata mesajları
🏷 Etiketler
Laravel PHP RESTful API Enum Exception Handling JSON APİ