Beril Tezcan workspace
Yazılım Mühendisi & QA Mühendisi

Beril Tezcan

i2i'de yazılım test mühendisiyim; QA ve test otomasyonu üzerine çalışıyorum. ASP.NET Core ve .NET ile backend geliştirme geçmişim var - ve her gün öğrenmeye, üretmeye ve gelişmeye devam ediyorum.

Software

What Really Happens When You Call an API?

A simple journey through HTTP requests, middleware, controllers, services, and databases in ASP.NET Core.
B
Beril Tezcan Yazılım Mühendisi · QA Mühendisi 👁 424 görüntülenme
What Really Happens When You Call an API?
Bağlantı kopyalandı!

Bir web uygulamasında bir butona tıkladığımızda veya bir API isteği gönderdiğimizde, arka planda pek çok şey gerçekleşir.

Diyelim ki yeni bir sipariş oluşturmak istiyoruz:

POST /api/orders

İlk bakışta sadece bir HTTP isteği gönderiyor gibi görünebiliriz. Ancak istek sunucuya ulaştıktan sonra birkaç farklı katmandan geçer.

Bu yolculuğu şu şekilde görselleştirebiliriz:

İstemci
   ↓
HTTP İsteği
   ↓
Middleware
   ↓
Controller
   ↓
Service
   ↓
Repository
   ↓
Veritabanı
   ↓
HTTP Yanıtı

Peki, her adımda tam olarak ne oluyor?

1. İstemci Bir HTTP İsteği Gönderir

İlk olarak, frontend veya başka bir uygulama API'ye bir istek gönderir.

Örneğin:

POST /api/orders
Content-Type: application/json

{
    "productId": 10,
    "quantity": 2
}

İstemci, sunucuya yeni bir sipariş oluşturmak istediğini söylüyor.

Bir HTTP isteği sadece bir URL'den ibaret değildir. HTTP metodu, başlıklar, gövde ve diğer bilgileri içerebilir.

2. İstek Middleware'dan Geçer

İstek bir ASP.NET Core uygulamasına ulaştığında, doğrudan Controller'a gitmez.

Önce middleware pipeline'ından geçer.

Örneğin:

app.UseAuthentication();
app.UseAuthorization();

Authentication, kullanıcının kim olduğunu kontrol eder.

Authorization ise bu kullanıcının istenen işlemi yapmaya yetkisi olup olmadığını kontrol eder.

Middleware'ı, uygulamamızın girişindeki bir dizi kontrol noktası olarak düşünebiliriz.

Gerekli kontroller tamamlandıktan sonra, istek pipeline'da ilerlemeye devam eder.

3. İstek Controller'a Ulaşır

ASP.NET Core daha sonra isteği hangi Controller ve Action'ın işleyeceğini belirler.

Örneğin:

[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IOrderService _orderService;

    public OrdersController(IOrderService orderService)
    {
        _orderService = orderService;
    }

    [HttpPost]
    public async Task<IActionResult> Create(CreateOrderRequest request)
    {
        await _orderService.CreateOrder(request);

        return StatusCode(201);
    }
}

İstemci şunu gönderdiğinde:

POST /api/orders

ASP.NET Core isteği OrdersController içindeki Create metoduna yönlendirir.

Dikkat edin, Controller servisi kendisi oluşturmuyor. ASP.NET Core, IOrderService'i Dependency Injection ile sağlıyor.

Ancak burada önemli bir nokta var:

Controller'ın her şeyi yapması gerekmez.

İdeal olarak, Controller isteği almalı ve gerekli işi uygun servise aktarmalıdır.

4. Controller Servisi Çağırır

İş mantığımızı bir Service katmanında tutabiliriz.

Örneğin:

public class OrderService
{
    private readonly IOrderRepository _repository;

    public OrderService(IOrderRepository repository)
    {
        _repository = repository;
    }

    public async Task CreateOrder(CreateOrderRequest request)
    {
        var order = new Order
        {
            ProductId = request.ProductId,
            Quantity = request.Quantity
        };

        await _repository.AddAsync(order);
    }
}

Artık Controller'ın veritabanı işleminin nasıl çalıştığını bilmesine gerek yok.

Sadece Servisi çağırıyor:

await _orderService.CreateOrder(request);

Bu ayrım, kodumuzun daha anlaşılır, bakımı kolay ve test edilebilir olmasını sağlar.

5. Servis Repository'yi Çağırır

Eğer Servis veriyi veritabanında saklamak isterse, bir Repository kullanabilir.

Örneğin:

public class OrderRepository : IOrderRepository
{
    private readonly AppDbContext _context;

    public OrderRepository(AppDbContext context)
    {
        _context = context;
    }

    public async Task AddAsync(Order order)
    {
        await _context.Orders.AddAsync(order);
        await _context.SaveChangesAsync();
    }
}

Burada, siparişi veritabanına kaydetmek için Entity Framework Core kullanıyoruz.

Servis, verinin nasıl saklandığına dair teknik detayları bilmek zorunda değildir.

6. Veritabanı İşlemi Gerçekleşir

Repository şunu çalıştırdığında:

await _context.SaveChangesAsync();

Entity Framework Core gerekli SQL komutlarını oluşturur ve veritabanına gönderir.

Kabaca şöyle görünebilir:

INSERT INTO Orders (ProductId, Quantity)
VALUES (10, 2);

Veritabanı işlemi tamamlandıktan sonra, sonuç uygulamaya döndürülür.

7. Yanıt İstemciye Geri Döner

Veritabanı işlemi başarıyla tamamlandıktan sonra, Servis işini bitirir.

Controller daha sonra bir HTTP yanıtı döndürür:

return StatusCode(201);

İstemci şunu alabilir:

HTTP/1.1 201 Created

Artık istemci, siparişin başarıyla oluşturulduğunu bilir.

Peki, Gerçekte Ne Oldu?

Sadece bir istek gönderdik:

POST /api/orders

Ancak bu isteğin arkasında tüm bu yolculuk gerçekleşti:

İstemci
   ↓
HTTP İsteği
   ↓
Middleware
   ↓
Controller
   ↓
Service
   ↓
Repository
   ↓
Entity Framework Core
   ↓
Veritabanı
   ↓
Yanıt
   ↓
İstemci

Bu, backend uygulamalarıyla çalışırken anlamamız gereken önemli şeylerden biridir.

Bir API sadece bir URL değildir.

Bir isteğin uygulama içinde nasıl ilerlediğini anlamak, sorunları ayıklamamıza, performansı iyileştirmemize, daha iyi kod tasarlamamıza ve uygulamalarımızı daha kolay sürdürmemize yardımcı olur.

Neden Bu Katmanları Ayırıyoruz?

Neden her şeyi doğrudan Controller'ın içine koymuyoruz?

Şöyle bir Controller hayal edin:

[HttpPost]
public async Task<IActionResult> Create(CreateOrderRequest request)
{
    // validation
    // business logic
    // database query
    // logging
    // email
    // other operations...

    return Ok();
}

Bu yaklaşım küçük bir proje için işe yarayabilir.

Ancak uygulama büyüdükçe, Controller'lar hızla yüzlerce satır uzunluğuna ulaşabilir.

Bunun yerine, sorumlulukları ayırabiliriz:

Controller  → İsteği işler
Service     → İş mantığını içerir
Repository  → Veri erişimini yönetir
Veritabanı  → Veriyi saklar

Bu, uygulamanın farklı parçalarını değiştirmeyi, test etmeyi ve sürdürmeyi kolaylaştırır.

Son Düşünce

Bir kullanıcı için bir API isteği göndermek sadece bir butona tıklamaktan ibaret olabilir.

Ancak bir geliştirici için, o tıklama bir yolculuğu başlatır.

Bu yolculuğu ne kadar iyi anlarsak, uygulamalarımızı ayıklamak, geliştirmek ve ölçeklendirmek o kadar kolaylaşır.

Bir dahaki sefere bir API çağırdığınızda unutmayın: o tek isteğin arkasında çok daha fazlası oluyor.

Yorumlar

i
iboware@gmail.com
11.09.2026 15:11
Güzel analiz, özellikle istek yaşam döngüsünü sorumlulukların ayrımıyla bağlantılandırma şekliniz. Bir sonraki yazıda ele alınabilecek ilginç bir konu da doğrulama, istisna işleme ve işlem sınırlarının bu akışa nasıl uyduğu olabilir. 👌