REST API'lerde Hata Yönetimi ve Hata Kodları
Bir API'nin kalitesi, yalnızca başarılı yanıtlarında değil, hata durumlarındaki davranışında da kendini gösterir. İyi tasarlanmış hata yönetimi; istemcinin sorunu anlamasını, kullanıcıya anlamlı mesaj göstermesini ve gerektiğinde otomatik olarak yeniden denemesini sağlar. Kötü tasarlanmış hata yanıtları ise hata ayıklamayı zorlaştırır ve güvenlik açıklarına yol açar.
1. HTTP Durum Kodları: İlk Katman
HTTP durum kodları, hatanın türü hakkında istemciye ilk ipucunu verir. Temel ayrım kritiktir: 4xx istemcinin düzeltebileceği, 5xx sunucunun düzeltmesi gereken hataları temsil eder.
| Kod | Anlam | Kullanım |
|---|---|---|
| 400 | Bad Request | Validasyon hatası, bozuk JSON |
| 401 | Unauthorized | Token eksik/geçersiz |
| 403 | Forbidden | Kimlik doğrulandı, yetki yok |
| 404 | Not Found | Kaynak mevcut değil |
| 409 | Conflict | Aynı e-posta ile kayıt, eşzamanlı güncelleme |
| 422 | Unprocessable Entity | Söz dizimi doğru, iş mantığı hatası |
| 429 | Too Many Requests | Rate limit aşıldı |
| 500 | Internal Server Error | Beklenmedik sunucu hatası |
| 503 | Service Unavailable | Bakım, aşırı yük |
2. Problem Details (RFC 9457): Standart Hata Formatı
Yalnızca durum kodu dönmek yeterli değildir; istemcinin hatayı anlaması için yapılandırılmış bir gövde gerekir. Problem Details, bu ihtiyacı karşılayan endüstri standardıdır.
json
{
"type": "https://example.com/probs/validation-error",
"title": "Validation Error",
"status": 400,
"detail": "Bir veya daha fazla alan geçersiz.",
"instance": "/api/orders",
"errors": {
"customerName": ["Müşteri adı boş olamaz."],
"totalAmount": ["Tutar pozitif olmalıdır."]
},
"traceId": "0HN7GNR1Q8Q7D:00000001"
}
Content-Type: application/problem+json
traceId gibi genişletme üyeleri, destek ekibinin log'larda ilgili isteği bulmasını sağlar.
3. İş Mantığı Hataları için Özel Hata Kodları
HTTP durum kodları genel kategorileri temsil eder. İstemcinin iş mantığına özel hataları ayırt edebilmesi için uygulamaya özel hata kodları tanımlanmalıdır.
json
{
"type": "https://example.com/probs/insufficient-stock",
"title": "Insufficient Stock",
"status": 409,
"detail": "Ürün stoğu yetersiz. Mevcut: 3, İstenen: 10.",
"errorCode": "ORDER_STOCK_INSUFFICIENT",
"availableQuantity": 3,
"requestedQuantity": 10
}
Kurallar:
-
Büyük harf ve alt çizgi kullanın (
ORDER_STOCK_INSUFFICIENT). -
Hiyerarşik yapı kurun (
PAYMENT_CARD_EXPIRED). -
Hata kodlarını sürümler arasında değiştirmeyin.
-
Her kodu dokümante edin.
4. Güvenlik: Hata Mesajlarında Bilgi Sızıntısını Önleme
Hata mesajları, saldırganlara sistem hakkında bilgi sızdırabilir.
❌ Güvensiz:
json
{
"status": 500,
"detail": "SqlException: Invalid column name 'user_password' at System.Data.SqlClient..."
}
✅ Güvenli:
json
{
"type": "https://example.com/probs/internal-error",
"title": "Internal Server Error",
"status": 500,
"detail": "Beklenmedik bir hata oluştu. Lütfen daha sonra tekrar deneyin.",
"traceId": "0HN7GNR1Q8Q7D:00000001"
}
Kurallar: Stack trace, veritabanı hata mesajları, dosya yolları ve sunucu isimleri asla istemciye gönderilmemeli; gerçek detaylar sunucu log'larına yazılmalıdır.
5. .NET'te Merkezi Hata Yönetimi
.NET 8+ IExceptionHandler ile:
csharp
public class GlobalExceptionHandler : IExceptionHandler
{
public async ValueTask<bool> TryHandleAsync(
HttpContext context, Exception exception, CancellationToken ct)
{
var problem = exception switch
{
NotFoundException => new ProblemDetails
{
Title = "Kaynak Bulunamadı",
Status = StatusCodes.Status404NotFound
},
ValidationException v => new ValidationProblemDetails(v.Errors)
{
Title = "Doğrulama Hatası",
Status = StatusCodes.Status400BadRequest
},
_ => new ProblemDetails
{
Title = "Sunucu Hatası",
Status = StatusCodes.Status500InternalServerError,
Detail = "Beklenmedik bir hata oluştu."
}
};
problem.Extensions["traceId"] = context.TraceIdentifier;
context.Response.StatusCode = problem.Status ?? 500;
await context.Response.WriteAsJsonAsync(problem, ct);
return true;
}
}
// Program.cs
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
builder.Services.AddProblemDetails();
app.UseExceptionHandler();
6. En İyi Pratikler
| Pratik | Açıklama |
|---|---|
| Tutarlı format kullanın | Tüm hatalarda Problem Details. |
| Doğru durum kodu seçin | 4xx ve 5xx ayrımına dikkat edin. |
| Özel hata kodları tanımlayın | İş mantığı hatalarını ayırt edin. |
| Güvenli mesajlar yazın | Stack trace ve iç detayları asla göndermeyin. |
| Trace ID ekleyin | Log'larda ilgili isteği bulmayı kolaylaştırın. |
| Merkezi yönetin | IExceptionHandler ile tüm hataları tek noktadan yönetin. |
| Dokümante edin | Her hata kodunu API dokümanında belirtin. |
Sonuç
REST API'lerde hata yönetimi, API'nin kullanılabilirliğini ve güvenliğini belirleyen en kritik unsurlardan biridir. Doğru HTTP durum kodları, Problem Details standardı, özel hata kodları, güvenli mesajlar ve merkezi yönetim ile istemcilerin sorunları anlamasını ve düzeltmesini sağlayabilirsiniz. Unutmayın: İyi bir API, hata durumunda bile kullanıcıyı yarı yolda bırakmaz; ona ne olduğunu ve ne yapması gerektiğini açıkça söyler.