Backend, REST API ve entegrasyon geliştirme

Backend, bir uygulamanın kullanıcıya görünmeyen tarafıdır: iş kurallarını çalıştıran sunucu kodu, verinin tutulduğu veri tabanı ve mobil uygulamanın, web arayüzünün ya da başka sistemlerin konuştuğu API. REST API'leri önce sözleşmesini (OpenAPI belgesi) yazarak geliştiriyor; ödeme, e-fatura, kargo ve ERP gibi dış sistemlerle entegrasyonları tekrar eden bildirim, zaman aşımı ve habersiz sürüm değişikliği gibi gerçek hayat hatalarına dayanıklı kuruyoruz.

Güncellendi:

Kısaca

  • API'nin sözleşmesi koddan önce OpenAPI belgesi olarak yazılır; hata yanıtları RFC 9457 biçiminde, zamanlar UTC ve RFC 3339 biçimindedir.
  • Entegrasyonda bildirimin (webhook) iki kez, geç ya da sırasız gelmesi normal kabul edilir; alıcı taraf aynı olayı ikinci kez işlemeyecek biçimde yazılır.
  • Çoğu projede mikroservis gerekmez; modül sınırları net tek bir uygulama daha ucuza işletilir ve gerektiğinde bölünebilir.
  • API güvenliğinde en sık açık, kullanıcının istekteki kimliği değiştirerek başkasına ait kaydı okuyabilmesidir (OWASP API1:2023).
Bu sayfada
  1. Backend geliştirme hangi parçalardan oluşur?
  2. REST API'yi nasıl tasarlıyoruz?
  3. API güvenliğinde en sık hangi hata yapılır?
  4. Üçüncü taraf entegrasyonlarında sorun nerede çıkar?
  5. Mikroservis mimarisi ne zaman gerekir, ne zaman gerekmez?
  6. Veri tabanı tasarımında neye dikkat ediyoruz?
  7. API kayıtları bir anlaşmazlıkta işe yarar mı?
  8. Sistem mimarisi ve teslim: elinize ne geçer?

Backend işleri bize çoğunlukla üç biçimde gelir: yeni bir mobil ya da web uygulamasının sunucu tarafı; iki sistemin (örneğin e-ticaret sitesiyle muhasebe yazılımının) birbiriyle konuşması; ya da büyüdükçe yavaşlayan eski bir sunucu uygulaması. Üçüncüsü çoğu zaman bir modernizasyon işidir; bu sayfa ilk ikisini anlatıyor.

Backend geliştirme hangi parçalardan oluşur?

Backend; API katmanı, iş kuralları, veri tabanı, arka plan işleri ve dış sistem bağlantılarından oluşur. Her parçanın kendine özgü bir hata türü vardır:

ParçaNe yaparSık gördüğümüz hata
API katmanıİstekleri alır, kimliği ve yetkiyi doğrular, yanıtı biçimlerYetki kontrolünün yalnızca arayüzde yapılması
İş kurallarıFiyat, stok, onay, durum geçişleriAynı kuralın üç ayrı yerde, üç farklı biçimde yazılması
Veri tabanıKalıcı veri, ilişkiler, kısıtlarBütünlüğün yalnızca uygulama koduna emanet edilmesi
Arka plan işleri, kuyruklarE-posta, rapor, entegrasyon gönderimleriBaşarısız işin sessizce kaybolması
Dış sistem bağlantılarıÖdeme, e-fatura, kargo, SMS, ERPZaman aşımı ve yeniden deneme planının olmaması

REST API'yi nasıl tasarlıyoruz?

REST API'yi, kullanan geliştiricinin davranışı dokümana bakmadan tahmin edebileceği biçimde tasarlarız: sözleşme önce yazılır; hata, sürüm, zaman ve para için tek kural vardır.

  1. Sözleşme önce yazılır. Uç noktalar, alanlar, hata kodları ve örnekler bir OpenAPI belgesinde tanımlanır (güncel sürüm 3.2.0, Eylül 2025). Mobil ve web ekibi sunucu hazır olmadan bu sözleşmeyle çalışmaya başlar; sunucu otomatik testlerle belgeye karşı doğrulanır.
  2. Kaynak adları ve sürüm. GET /v1/orders/{id}, POST /v1/orders. Geriye uyumsuz değişiklik yeni sürümle gelir, eski sürümün kapanış tarihi önceden duyurulur; güncellenmemiş telefonlardaki uygulamalar eski sürümü aylarca çağırmaya devam eder.
  3. Hatalar tek biçimde döner. RFC 9457'nin tanımladığı application/problem+json biçimi:
    {
      "type": "https://api.example.com/problems/stok-yetersiz",
      "title": "Stok yetersiz",
      "status": 409,
      "detail": "Ürün 88 için istenen 5, mevcut 2.",
      "instance": "/v1/orders/req-9f2c"
    }
  4. Yeniden denemeye dayanıklılık. RFC 9110'a göre GET, PUT ve DELETE idempotenttir; aynı istek iki kez gelse de amaçlanan sonuç değişmez. POST değildir. Bağlantı kopup istemci isteği yinelediğinde siparişin iki kez oluşmaması için POST isteklerinde Idempotency-Key başlığı kabul ederiz. Başlık IETF'te taslak olarak kaldı, RFC olmadı; ama ödeme sağlayıcılarında yaygındır.
  5. Sayfalama ve sınırlar. Büyük listelerde imleç (cursor) tabanlı sayfalama; aşırı istekte 429 ve Retry-After başlığı. Sınırı olmayan bir liste uç noktası, OWASP'ın "sınırsız kaynak tüketimi" başlığının (API4:2023) tipik örneğidir.
  6. Zaman ve para. Zamanlar UTC ve RFC 3339 biçiminde döner: 2026-09-27T09:15:42Z. Para, kuruş cinsinden tam sayı ya da metin olarak yazılmış ondalık ("990.00") ve para birimi koduyla gönderilir; JSON'da kayan noktalı sayıya bırakılmaz.

API güvenliğinde en sık hangi hata yapılır?

En sık hata, oturum açmış bir kullanıcının istekteki kimliği değiştirerek başkasına ait kaydı okuyabilmesidir. OWASP API Security Top 10'un 2023 listesinde bu, birinci sıradaki nesne düzeyinde yetki ihlalidir (Broken Object Level Authorization).

Örnek: GET /v1/invoices/1043 isteği, faturanın isteği yapan müşteriye ait olup olmadığına bakılmadan yanıtlanıyorsa 1044'ü deneyen herkes başka bir müşterinin faturasını görür. Kimliği tahmin edilemez yapmak (UUID) sorunu gizler ama çözmez; sahiplik her istekte sunucuda kontrol edilir. Kabul testlerine, bir kullanıcının oturumuyla başkasının kaydını okumaya, değiştirmeye ve silmeye çalışan senaryolar koyarız; hepsi 403 ya da 404 dönmelidir.

Kimlik doğrulamada OAuth 2.0 kullanılıyorsa RFC 9700'ün (Ocak 2025) önerilerini izleriz: kullanıcı parolasını istemcinin topladığı "resource owner password" akışı kullanılmaz; mobil uygulama ve tarayıcı gibi açık istemcilerde yetkilendirme kodu akışı PKCE ile çalışır.

Üçüncü taraf entegrasyonlarında sorun nerede çıkar?

Sorun genellikle her şeyin yolunda gittiği senaryoda değil; karşı tarafın yavaşladığı, aynı bildirimi iki kez gönderdiği ya da habersiz sürüm değiştirdiği anda çıkar. Ödeme kuruluşu, e-fatura özel entegratörü, kargo, SMS sağlayıcısı ya da ERP yazılımı olsun, aynı durumları planlarız:

DurumNe olurÖnlem
Bildirim (webhook) tekrar gelirSipariş iki kez onaylanır, stok iki kez düşerOlay kimliği kaydedilir, işlenmiş olay ikinci kez işlenmez. Stripe canlı ortamda teslim edemediği olayı üç güne kadar yeniden dener
Bildirimler sırasız gelir"Ödendi" olayı "oluşturuldu"dan önce işlenirSıraya güvenilmez; eksik nesne sağlayıcının API'sinden çekilir, durum geçişleri kontrol edilir
Sahte bildirimÖdenmemiş sipariş ödenmiş sayılırİmza ham istek gövdesi üzerinden doğrulanır; zaman damgası toleransı (Stripe kütüphanelerinde varsayılan 5 dakika) için sunucu saati NTP ile senkron tutulur
Karşı taraf yavaş ya da kapalıKullanıcının isteği dakikalarca asılı kalırKısa zaman aşımı, giderek artan aralıklarla yeniden deneme, kuyruk; bildirimi alan uç önce 2xx döner, işi arka planda yapar
İki sistemin kayıtları tutmazAy sonunda toplamlar farklı çıkarGünlük mutabakat işi: iki taraftaki kayıtlar kimlik ve tutarla eşleştirilir, farklar raporlanır
Karakter kodlamasıERP'den gelen dosyada "ş" yerine anlamsız karakterEski sistemlerin Windows-1254 ya da ISO-8859-9 çıktısı içeri alınırken açıkça UTF-8'e çevrilir

Veri tabanı değişikliği ile dışarı gidecek mesajdan biri başarılı, diğeri başarısız olursa iki sistem ayrışır. Bunu önlemek için giden mesajı aynı işlem (transaction) içinde bir giden kutusu tablosuna yazar, ayrı bir işçiyle göndeririz (transactional outbox). Mesaj en az bir kez gider; tekrarı tanımak alıcı tarafın olay kimliği kuralıyla sağlanır.

Ticari SMS veya e-posta gönderen sistemlerde onayların İleti Yönetim Sistemi (İYS) ile eşlenmesi de bir entegrasyon kalemidir; hangi iletinin ticari sayıldığını hukukçunuz değerlendirir.

Mikroservis mimarisi ne zaman gerekir, ne zaman gerekmez?

Çoğu projede gerekmez. Mikroservis mimarisi uygulamayı ağ üzerinden konuşan, ayrı dağıtılan küçük servislere böler ve dağıtık sistemin maliyetini getirir: servisler arası ağ hataları, birden çok veri tabanında tutarlılık, her servis için ayrı izleme ve dağıtım hattı. Martin Fowler'ın gözlemi de bu yönde: başarılı mikroservis örneklerinin neredeyse hepsi büyüyüp bölünen bir monolitle başlamış; sıfırdan mikroservis olarak kurulduğunu duyduğu sistemlerin ise neredeyse hepsi ciddi sorun yaşamış.

Mikroservis düşünülebilirTek uygulama yeterli
Birbirinden bağımsız yayın yapması gereken birden çok ekip varTek ekip ya da birkaç geliştirici
Bir bölümün yük profili diğerlerinden çok farklı (görüntü işleme gibi)Yük dengeli, darboğaz veri tabanında
Bir bölümün çökmesinin diğerlerini durdurmaması ölçülmüş bir ihtiyaç"İleride büyürüz" beklentisi

Varsayılan yaklaşımımız modüler monolittir: tek dağıtım, ama modül sınırları kodda net, her modülün kendi tabloları ve arayüzü var. Ölçülmüş bir ihtiyaç doğduğunda bir modülü ayrı servise çıkarmak bu düzende görece kolaydır. Rapor üretimi gibi ağır işleri ayrı bir işçi sürecine almak ise mikroservis değildir ve çoğu zaman yeterlidir.

Veri tabanı tasarımında neye dikkat ediyoruz?

Veri, uygulamadan uzun yaşar: uygulama iki kez yeniden yazılır, tablolar yerinde kalır. Bu yüzden:

  • Bütünlük veri tabanında zorlanır. Yabancı anahtar, UNIQUE ve CHECK kısıtları sayesinde uygulamadaki bir hata tutarsız kayıt üretemez.
  • Para kayan noktalı sayıda tutulmaz. NUMERIC(12,2) ya da kuruş cinsinden tam sayı.
  • Zaman saat dilimiyle tutulur. PostgreSQL'de timestamptz değeri içeride UTC olarak saklar, gösterirken oturumun saat dilimine çevirir. Zaman kurallarımızın ayrıntısı özel yazılım geliştirme sayfasında.
  • Karakter seti. MySQL'de utf8, 3 baytlık ve kullanımdan kaldırılmış utf8mb3'ün takma adıdır; MySQL belgeleri yeni uygulamalar için utf8mb4'ü önerir.
  • Türkçe büyük-küçük harf. Java'da "title".toUpperCase(), Türkçe yerel ayarla çalışan bir sunucuda "TİTLE" döndürür. Ekrandaki metinde doğrusu budur, ama sistem anahtarlarında ve e-posta karşılaştırmasında hata üretir; bu değerlerde Locale.ROOT kullanılır, arama için uygun sıralama kuralı (collation) seçilir.
  • Şema değişikliği sürümlüdür. Her değişiklik, geri alma adımıyla birlikte numaralı bir migration dosyasıdır; canlı veri tabanında elle ALTER TABLE çalıştırılmaz.
  • Silme bir tasarım kararıdır. "Silindi" diye işaretlenmiş kayıt (soft delete), kişisel veri açısından silinmiş sayılmaz. KVKK m.7 kapsamında silme, yok etme ya da anonimleştirme gerekiyorsa bunu yapan iş ve yedeklerdeki kopyanın ömrü ayrıca tasarlanır.

API kayıtları bir anlaşmazlıkta işe yarar mı?

Bir API'nin kayıtları, ancak tek bir isteği baştan sona izlemeye yetiyorsa işe yarar. Her isteğe bir istek kimliği (request_id) verir, bu kimliği API, kuyruk, dış sistem çağrısı ve denetim kaydı boyunca taşırız. Denetim kaydının alanlarını özel yazılım sayfamızda anlattık; API tarafında ayrıca:

  • İstemcinin IP adresiyle birlikte kaynak portu da yazılır. CGNAT arkasında aynı IP adresini birçok abone paylaşır; RFC 6302 bu yüzden internete açık sunuculara kaynak portu ve izlenebilir bir saat kaynağından alınmış, tercihen UTC zaman damgasını kaydetmeyi önerir. 5651 sayılı Kanun'daki trafik bilgisi tanımı da (m.2/1-j) IP adresiyle birlikte kaynak ve hedef port bilgisini sayar; "kaynak ve hedef" ibaresi 31.07.2026'da yürürlüğe giren 7590 sayılı Kanunla eklendi. Nginx'in varsayılan kayıt biçiminde kaynak port yoktur, ayrıca eklenir.
  • Yük dengeleyici ya da CDN arkasında sunucu ara katmanın adresini görür; gerçek istemci adresi ve portu, ancak ara katman bunları bir başlıkta iletiyor ve başlık yalnızca ondan kabul ediliyorsa doğru kaydedilir.
  • Dış sistemlere giden istekler ve gelen yanıtlar; parola, anahtar ve kart bilgisi ayıklanarak saklanır. "Karşı taraf bildirimi hiç göndermedi" tartışması çoğu zaman bu kayıtla kapanır.

Bu kayıtların bir uyuşmazlıkta nasıl okunduğunu log kayıtlarının güvenilirliği yazısında, bir olayda nasıl incelendiğini log analizi sayfasında anlatıyoruz.

Sistem mimarisi ve teslim: elinize ne geçer?

Sistem mimarisi bir diyagramdan çok, kararların gerekçesiyle yazılı olmasıdır. Teslimde aldıklarınız:

  • OpenAPI sözleşmesi ve her uç nokta için örnek istek ve yanıtlar.
  • Veri modeli şeması ve migration geçmişi.
  • Mimari karar kayıtları (ADR): "neden PostgreSQL", "neden kuyruk", "neden mikroservis değil"; her biri tarih, değerlendirilen seçenekler ve gerekçeyle.
  • Entegrasyon envanteri: dış sistem, ortam, anahtarın saklandığı yer (değeri değil), sağlayıcının destek kanalı ve sürüm politikası.
  • Çalıştırma kılavuzu: dağıtım, yedekten geri dönüş, bir entegrasyon durduğunda yapılacaklar.
  • Otomatik testler ve bir yük testi sonucu: hangi yükte, hangi yanıt süresi.

Kod deposu, bulut ve sağlayıcı hesapları iş sahibi adına açılır. Sürekli entegrasyon ve dağıtım hattının kurulumu modernizasyon, bulut ve DevOps sayfasının konusu; bu işlerin kabul kriterlerini baştan yazmak için proje danışmanlığı ve teknik şartname sayfasına bakabilirsiniz.

Sık sorulan sorular

REST API mi, GraphQL mi kullanmalıyız?

Çoğu iş uygulamasında REST yeterlidir ve daha kolay işletilir: HTTP önbelleği, durum kodları ve yaygın araçlar hazır gelir. GraphQL, farklı ekranların aynı veriden çok farklı alt kümeler istediği, istemcinin çok olduğu durumlarda avantaj sağlar; buna karşılık sorgu maliyetini sınırlamak, önbelleği ve alan düzeyinde yetkiyi kurmak ek iş ister. Kararı istemcilerin gerçek veri ihtiyacına bakarak veririz.

API entegrasyonu için karşı taraftan neler istemeliyiz?

Güncel API dokümanı ve sürüm politikası, canlıdan ayrı bir test ortamı ve test anahtarları, istek sınırları, bildirim imzasının nasıl doğrulanacağı, yeniden deneme davranışı, hata kodlarının listesi ve teknik destek kanalı. Test ortamında desteklenmeyen senaryolar da açıkça söylenmeli. Bu listeyi entegrasyonun başında yazılı alırız; eksik kalan her madde canlıya geçişte sürpriz olarak döner.

Mevcut yazılımımıza API eklenebilir mi?

Çoğu zaman evet. En güvenli yol, mevcut uygulamanın iş kurallarını kullanan ince bir API katmanıdır. Başka bir sistemin doğrudan veri tabanınıza yazması kuralları atlar ve zamanla tutarsız kayıt üretir; bunu yalnızca sınırlı okuma için öneririz. Eski uygulama API eklemeyi zorlaştıracak durumdaysa adım adım dönüştürme seçeneklerini modernizasyon ve DevOps sayfamızda anlattık.

PostgreSQL mi MongoDB mi seçmeliyiz?

Sipariş, fatura, stok, kullanıcı gibi işlemsel veri için varsayılan önerimiz PostgreSQL gibi ilişkisel bir veri tabanıdır: kısıtlar, işlemler (transaction) ve raporlama hazır gelir, JSON alanlarla esnek veri de tutulabilir. MongoDB gibi belge tabanlı veri tabanları, şeması kayıttan kayda gerçekten değişen içerikte ya da yüksek hacimli olay kayıtlarında anlam kazanır. Seçimi veri modelini çizdikten sonra, gerekçesiyle yazarız.

Webhook bildirimi neden bazen iki kez geliyor?

Sağlayıcılar teslimi güvenceye almak için olayları "en az bir kez" gönderir: sunucunuz zamanında 2xx yanıtı vermezse ya da yanıt yolda kaybolursa aynı olay yeniden gelir. Stripe örneğin canlı ortamda teslim edemediği olayı üç güne kadar yeniden dener ve olayların sırasını garanti etmez. Doğru çözüm tekrarı önlemeye çalışmak değil, alıcı tarafı aynı olay kimliğini ikinci kez işlemeyecek biçimde yazmaktır.

Kaynaklar

  1. RFC 9110: HTTP Semantics (idempotent yöntemler, 9.2.2) — IETF
  2. RFC 9457: Problem Details for HTTP APIs — IETF
  3. OpenAPI Specification v3.2.0 — OpenAPI Initiative
  4. OWASP API Security Top 10 (2023) — OWASP Foundation
  5. RFC 6302: Logging Recommendations for Internet-Facing Servers — IETF
  6. Receive Stripe events in your webhook endpoint — Stripe Docs
  7. MonolithFirst — martinfowler.com
  8. 5651 sayılı İnternet Ortamında Yapılan Yayınların Düzenlenmesi Hakkında Kanun (m.2/1-j) — mevzuat.gov.tr