API Entegrasyonuna Giriş: Temel Kavramlar ve HTTP

Modern yazılım dünyasında hiçbir sistem artık tek başına çalışmıyor. Kullandığın bulut servisleri, izleme araçları, otomasyon scriptleri ve iş uygulamaları birbirleriyle konuşmak zorunda. Bu konuşmanın dili ise büyük ölçüde API’ler. Sysadmin olarak sen de er ya da geç bir servisi başka bir servisle entegre etmen, bir REST endpoint’ine veri çekmen ya da kendi yazdığın scriptten bir platforma veri göndermenin yolunu bulman gerekecek. Bu yazıda API dünyasına pratik bir giriş yapıyoruz; teorik olmayan, gerçekten kullanabileceğin bilgilerle.

API Nedir ve Neden Önemli

API, “Application Programming Interface” kelimelerinin kısaltması. Türkçeye “Uygulama Programlama Arayüzü” diye çeviriyorlar ama bu çeviri pek bir şey ifade etmiyor açıkçası. Daha anlaşılır şekilde söylersek: API, iki yazılımın birbirleriyle nasıl konuşacağını tanımlayan bir sözleşme.

Restoran analojisini herkes yapar ama çünkü gerçekten işe yarıyor: Mutfağa gidip yemek istemiyorsun, garsonla konuşuyorsun. Garson senin isteğini mutfağa iletiyor, mutfak hazırlıyor, garson sana getiriyor. Burada garson API, mutfak ise arka taraftaki sistem. Sen mutfağın nasıl çalıştığını bilmek zorunda değilsin.

Sysadmin perspektifinden bakınca API’lerin önemi şu noktalarda ortaya çıkıyor:

  • Otomasyon: Monitoring sisteminin alert’lerini Slack kanalına göndermek
  • Entegrasyon: CMDB’den sunucu listesi çekip Ansible inventory oluşturmak
  • Raporlama: Cloud provider’dan maliyet verilerini çekip kendi dashboard’una yazmak
  • Webhook: Bir event gerçekleştiğinde başka bir sistemi tetiklemek

HTTP Protokolünün Temelleri

REST API’lerin büyük çoğunluğu HTTP protokolü üzerinde çalışıyor. HTTP’yi sadece web sayfası yüklemek için düşünme, aslında çok daha güçlü bir veri transfer protokolü.

HTTP Methods (HTTP Metodları)

Her HTTP isteği bir metod içeriyor. Bu metod yapılan işlemin ne olduğunu söylüyor:

  • GET: Veri okuma. Sunucuda hiçbir şey değişmiyor, sadece okuyorsun.
  • POST: Yeni kayıt oluşturma. Sunucuya yeni veri gönderiyorsun.
  • PUT: Var olan kaydı tamamen güncelleme. Tüm alanları yeniden yazıyorsun.
  • PATCH: Var olan kaydın bir kısmını güncelleme. Sadece değişen alanları gönderiyorsun.
  • DELETE: Kayıt silme.
  • HEAD: GET gibi ama response body dönmüyor, sadece header’lar geliyor. Dosya boyutu kontrol etmek için kullanışlı.
  • OPTIONS: Endpoint’in hangi metodları desteklediğini öğrenmek için.

HTTP Status Kodları

API response’larını anlamak için status kodlarını iyi bilmen gerekiyor:

  • 200 OK: Her şey yolunda, istek başarılı.
  • 201 Created: Yeni kayıt başarıyla oluşturuldu.
  • 204 No Content: Başarılı ama dönecek bir şey yok (genellikle DELETE sonrası).
  • 400 Bad Request: Gönderdiğin istek hatalı, eksik ya da format yanlış.
  • 401 Unauthorized: Kimlik doğrulama gerekli veya token geçersiz.
  • 403 Forbidden: Kimliğin doğrulandı ama bu kaynağa erişim iznin yok.
  • 404 Not Found: İstediğin kaynak bulunamadı.
  • 409 Conflict: Çakışma var, örneğin aynı isimle kayıt zaten mevcut.
  • 422 Unprocessable Entity: İstek formatı doğru ama içerik işlenemiyor.
  • 429 Too Many Requests: Rate limit aştın, yavaşla.
  • 500 Internal Server Error: Sunucu tarafında bir şeyler patladı.
  • 502 Bad Gateway: Ara sunucu upstream’den geçersiz yanıt aldı.
  • 503 Service Unavailable: Servis şu an çalışmıyor.

HTTP Headers

Header’lar istek ve yanıt hakkında meta bilgi taşıyor:

  • Content-Type: Gönderdiğin verinin formatı. application/json, text/plain, multipart/form-data gibi.
  • Accept: Hangi formatta yanıt istediğini belirtiyorsun.
  • Authorization: Kimlik doğrulama bilgisi. Bearer TOKEN ya da Basic base64encoded formatında.
  • X-API-Key: Bazı API’ler token’ı bu header’da bekliyor.
  • Content-Length: Gönderilen verinin byte cinsinden boyutu.
  • Cache-Control: Cache davranışını kontrol ediyor.

curl ile API Çağrıları

curl her sysadmin’in silahı. API test etmek için en hızlı araç:

# Basit GET isteği
curl https://jsonplaceholder.typicode.com/users/1

# Pretty print için jq ile birlikte kullan
curl -s https://jsonplaceholder.typicode.com/users/1 | jq .

# Verbose mod - header'ları ve tüm detayları görmek için
curl -v https://jsonplaceholder.typicode.com/users/1

# Sadece response header'larını göster
curl -I https://jsonplaceholder.typicode.com/users/1

# Custom header ekle
curl -H "Accept: application/json" 
     -H "X-Custom-Header: my-value" 
     https://api.example.com/data

# POST isteği - JSON body ile
curl -X POST https://jsonplaceholder.typicode.com/posts 
     -H "Content-Type: application/json" 
     -d '{"title": "Test Post", "body": "Content here", "userId": 1}'

# Authorization header ile
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.your-token" 
     https://api.example.com/protected/resource

# PUT isteği
curl -X PUT https://jsonplaceholder.typicode.com/posts/1 
     -H "Content-Type: application/json" 
     -d '{"id": 1, "title": "Updated Title", "body": "Updated body", "userId": 1}'

# DELETE isteği
curl -X DELETE https://jsonplaceholder.typicode.com/posts/1 
     -w "nHTTP Status: %{http_code}n"

curl’ün Önemli Parametreleri

  • -X: HTTP metodunu belirt (GET, POST, PUT, DELETE)
  • -H: Header ekle
  • -d: Request body gönder (data)
  • -s: Silent mod, progress bar gösterme
  • -v: Verbose, tüm detayları göster
  • -I: Sadece header’ları al (HEAD metodu)
  • -L: Redirect’leri takip et
  • -o dosya: Çıktıyı dosyaya yaz
  • -w: Belirli bilgileri formatlı yaz (http_code, time_total gibi)
  • -k: SSL sertifika doğrulamasını atla (sadece test ortamında!)
  • –max-time: Maksimum süre sınırı

Authentication Yöntemleri

API’lerde kimlik doğrulama birkaç farklı şekilde yapılıyor:

API Key

En basit yöntem. Bir string, bir header ya da query parameter olarak gönderiyorsun:

# Header üzerinden
curl -H "X-API-Key: sk-1234567890abcdef" 
     https://api.example.com/data

# Query parameter olarak (daha az güvenli)
curl "https://api.example.com/data?api_key=sk-1234567890abcdef"

# Örnek: OpenWeatherMap API
curl -s "https://api.openweathermap.org/data/2.5/weather?q=Istanbul&appid=YOUR_API_KEY" | jq '.main'

Basic Auth

Username ve password’ü base64 encode edip Authorization header’ına koyuyorsun:

# curl'ün -u parametresi bunu otomatik yapıyor
curl -u username:password https://api.example.com/resource

# Manuel olarak
echo -n "username:password" | base64
# Çıktı: dXNlcm5hbWU6cGFzc3dvcmQ=
curl -H "Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=" 
     https://api.example.com/resource

Bearer Token / JWT

Modern API’lerin büyük çoğunluğu bu yöntemi kullanıyor:

# Token'ı önce environment variable'a al, scripte gömme
export API_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

curl -H "Authorization: Bearer $API_TOKEN" 
     https://api.example.com/protected

# Token expire oluyorsa, refresh token ile yeni token al
curl -X POST https://api.example.com/auth/refresh 
     -H "Content-Type: application/json" 
     -d "{"refresh_token": "$REFRESH_TOKEN"}"

Python ile API Entegrasyonu

Bash ile basit işler yapabilirsin ama daha karmaşık senaryolar için Python çok daha uygun. requests kütüphanesi bu iş için standart:

# requests kütüphanesini kur
pip3 install requests

# Virtual environment kullanmak daha iyi pratik
python3 -m venv api-env
source api-env/bin/activate
pip install requests
import requests
import json
import os

# API base URL'ini ve token'ı environment'dan al
BASE_URL = "https://api.example.com/v1"
API_TOKEN = os.environ.get("API_TOKEN")

# Session kullanmak performansı artırıyor
session = requests.Session()
session.headers.update({
    "Authorization": f"Bearer {API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json"
})

# GET isteği
def get_servers():
    response = session.get(f"{BASE_URL}/servers")
    
    # Status code kontrol et
    if response.status_code == 200:
        return response.json()
    elif response.status_code == 401:
        raise Exception("Authentication failed. Token geçersiz veya expire olmuş.")
    elif response.status_code == 429:
        retry_after = response.headers.get("Retry-After", 60)
        raise Exception(f"Rate limit aşıldı. {retry_after} saniye bekle.")
    else:
        raise Exception(f"API hatası: {response.status_code} - {response.text}")

# POST isteği - yeni sunucu ekle
def create_server(name, region, size):
    payload = {
        "name": name,
        "region": region,
        "size": size
    }
    
    response = session.post(f"{BASE_URL}/servers", json=payload)
    response.raise_for_status()  # 4xx/5xx'te exception fırlat
    return response.json()

# Hata yönetimi ile daha sağlam kullanım
try:
    servers = get_servers()
    print(f"Toplam {len(servers)} sunucu bulundu")
    for server in servers:
        print(f"  - {server['name']} ({server['region']})")
except requests.exceptions.ConnectionError:
    print("API'ye bağlanılamadı. Network bağlantısını kontrol et.")
except requests.exceptions.Timeout:
    print("İstek zaman aşımına uğradı.")
except Exception as e:
    print(f"Hata: {e}")

Gerçek Dünya Senaryosu: Slack’e Alert Gönderme

Monitoring scriptine Slack entegrasyonu eklemek çok yaygın bir ihtiyaç. Slack’in Incoming Webhooks özelliği bunun en kolay yolu:

#!/bin/bash
# slack-alert.sh - Disk kullanımı yüksekse Slack'e bildir

WEBHOOK_URL="https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXX"
THRESHOLD=85
HOSTNAME=$(hostname)

# Disk kullanımını kontrol et
DISK_USAGE=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')

if [ "$DISK_USAGE" -gt "$THRESHOLD" ]; then
    # Slack mesajı için JSON payload oluştur
    PAYLOAD=$(cat <<EOF
{
    "text": ":warning: Disk Uyarısı",
    "attachments": [
        {
            "color": "danger",
            "fields": [
                {
                    "title": "Sunucu",
                    "value": "$HOSTNAME",
                    "short": true
                },
                {
                    "title": "Disk Kullanımı",
                    "value": "%$DISK_USAGE",
                    "short": true
                }
            ],
            "footer": "$(date '+%Y-%m-%d %H:%M:%S')"
        }
    ]
}
EOF
)

    # Webhook'a gönder
    RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" 
        -X POST "$WEBHOOK_URL" 
        -H "Content-Type: application/json" 
        -d "$PAYLOAD")
    
    if [ "$RESPONSE" == "200" ]; then
        echo "Slack bildirimi gönderildi"
    else
        echo "Slack bildirimi gönderilemedi. HTTP: $RESPONSE"
        exit 1
    fi
fi

Rate Limiting ve Retry Mantığı

Gerçek dünya API entegrasyonlarında en sık karşılaşılan sorunlardan biri rate limiting. İyi yazılmış bir script bunu handle etmeli:

#!/usr/bin/env python3
import requests
import time
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def api_request_with_retry(url, headers, max_retries=3, backoff_factor=2):
    """
    Retry ve exponential backoff ile API isteği.
    Rate limit durumunda otomatik bekleyip tekrar dener.
    """
    for attempt in range(max_retries):
        try:
            response = requests.get(url, headers=headers, timeout=30)
            
            # Rate limit
            if response.status_code == 429:
                retry_after = int(response.headers.get("Retry-After", 60))
                logger.warning(f"Rate limit. {retry_after} saniye bekleniyor...")
                time.sleep(retry_after)
                continue
            
            # Geçici sunucu hatası - retry mantıklı
            if response.status_code in [500, 502, 503, 504]:
                wait_time = backoff_factor ** attempt
                logger.warning(f"Sunucu hatası {response.status_code}. {wait_time}s sonra tekrar denenecek...")
                time.sleep(wait_time)
                continue
            
            # Başarılı ya da kalıcı hata - döndür
            return response
            
        except requests.exceptions.Timeout:
            wait_time = backoff_factor ** attempt
            logger.warning(f"Timeout. {wait_time}s sonra tekrar denenecek...")
            time.sleep(wait_time)
        except requests.exceptions.ConnectionError as e:
            logger.error(f"Bağlantı hatası: {e}")
            raise
    
    raise Exception(f"{max_retries} deneme sonrası başarısız")

# Kullanım
headers = {"Authorization": f"Bearer {os.environ['API_TOKEN']}"}
response = api_request_with_retry(
    "https://api.example.com/data",
    headers=headers,
    max_retries=3
)
data = response.json()

JSON ile Çalışmak

API’lerin büyük çoğunluğu JSON formatında veri dönüyor. Bash tarafında jq, Python tarafında json modülü hayat kurtarıyor:

# jq ile JSON parse etme

# Belirli bir alanı çek
curl -s https://jsonplaceholder.typicode.com/users/1 | jq '.name'

# Array'i iterate et
curl -s https://jsonplaceholder.typicode.com/users | jq '.[].email'

# Filtreleme - sadece belirli kullanıcıları al
curl -s https://jsonplaceholder.typicode.com/users | 
    jq '.[] | select(.address.city == "Gwenborough") | .name'

# Yeni bir yapıya dönüştür
curl -s https://jsonplaceholder.typicode.com/users | 
    jq '[.[] | {name: .name, email: .email, city: .address.city}]'

# Bash script içinde JSON oluştur - printf kullanmak daha güvenli
SERVER_NAME="web-01"
IP_ADDRESS="192.168.1.10"
JSON_PAYLOAD=$(printf '{"name":"%s","ip":"%s"}' "$SERVER_NAME" "$IP_ADDRESS")
echo "$JSON_PAYLOAD"

API Dokümantasyonu Okuma

Iyi API’lerin dokümantasyonu genellikle Swagger/OpenAPI formatında. Birkaç şeye dikkat et:

  • Base URL: Tüm endpoint’lerin önüne gelen adres. Versiyon numarasını içeriyor mu? (/v1, /v2)
  • Authentication: Nasıl kimlik doğrulama yapman gerekiyor?
  • Rate Limits: Dakika/saat/gün başına kaç istek yapabiliyorsun?
  • Pagination: Çok sayıda kayıt döndüren endpoint’ler nasıl sayfalama yapıyor?
  • Error Codes: API’ye özgü hata kodları var mı?

Pagination için dikkatli ol, çünkü sadece ilk sayfayı çekip işin bittiğini sanmak sık yapılan bir hata:

#!/bin/bash
# Tüm sayfaları çek ve birleştir
PAGE=1
ALL_DATA="[]"
API_URL="https://api.example.com/servers"
HEADERS=(-H "Authorization: Bearer $API_TOKEN" -H "Accept: application/json")

while true; do
    RESPONSE=$(curl -s "${HEADERS[@]}" "$API_URL?page=$PAGE&per_page=100")
    
    # Dönen kayıt sayısını kontrol et
    COUNT=$(echo "$RESPONSE" | jq 'length')
    
    if [ "$COUNT" -eq 0 ]; then
        echo "Sayfa $PAGE boş. Toplam sayfa: $((PAGE-1))"
        break
    fi
    
    echo "Sayfa $PAGE: $COUNT kayıt"
    # jq ile birleştir
    ALL_DATA=$(echo "$ALL_DATA $RESPONSE" | jq -s 'add')
    
    PAGE=$((PAGE + 1))
    sleep 0.5  # Rate limit için biraz bekle
done

echo "Toplam kayıt: $(echo "$ALL_DATA" | jq 'length')"

Güvenlik Pratikleri

API entegrasyonlarında güvenlik ihmal edilmemeli:

  • Token’ları asla koda gömme: Environment variable veya secret management aracı kullan (HashiCorp Vault, AWS Secrets Manager)
  • HTTPS kullan: HTTP üzerinden kimlik bilgisi gönderme
  • SSL doğrulamayı atlatma: -k ya da verify=False sadece geliştirme ortamında
  • Minimal yetki ilkesi: API key’ine sadece ihtiyaç duyduğu izinleri ver
  • Token rotasyonu: Uzun süre aynı token’ı kullanma, düzenli döndür
  • Logları filtrele: Token’ların log dosyalarına yazılmamasına dikkat et
# Token'ı environment variable olarak set et
export API_TOKEN=$(cat /run/secrets/api_token)

# Direkt scripte yazma - YANLIŞ
# API_TOKEN="sk-12345"  # Bu satırı asla koda yazma

# Log'larda token maskele
curl -H "Authorization: Bearer $API_TOKEN" https://api.example.com/data 
    2>&1 | sed 's/Authorization: Bearer [^ ]*/Authorization: Bearer [MASKED]/g'

Sonuç

API entegrasyonu artık sysadmin işinin ayrılmaz bir parçası. Bulut altyapıları, DevOps araçları ve modern servisler tamamen API üzerine kurulu. Bu temelleri kavradıktan sonra CMDB’ni otomatik güncelleyen, monitoring alert’lerini birden fazla kanala ileten, cloud maliyetlerini analiz eden güçlü otomasyon scriptleri yazabilirsin.

Başlamak için en iyi yol pratik yapmak. jsonplaceholder.typicode.com gibi ücretsiz test API’leri var, hemen curl ile denemeye başlayabilirsin. GitHub API, GitLab API ya da kullandığın cloud provider’ın API’si de mükemmel pratik ortamlar sunuyor.

Bir sonraki adım olarak REST API mimarisi, webhook’lar ve OAuth 2.0 akışları konularına bakmanı öneririm. Ama onlardan önce bugün öğrendiklerini bir script’te kullanmaya çalış. Öğrenmenin en hızlı yolu bu.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir