Azure Functions HTTP Trigger Yapılandırması ve En İyi Uygulamalar
Serverless dünyasına adım attığınızda, Azure Functions’ın HTTP Trigger özelliği muhtemelen ilk karşılaşacağınız ve en sık kullanacağınız yapı taşlarından biri olacak. Bir API endpoint’i kurmak, webhook almak ya da basit bir form gönderimini işlemek istediğinizde HTTP Trigger devreye giriyor. Bu yazıda, gerçek dünya senaryoları üzerinden Azure Functions HTTP Trigger yapılandırmasını tüm ayrıntılarıyla ele alacağız.
HTTP Trigger Nedir ve Neden Kullanırız?
Azure Functions’ta bir “trigger”, fonksiyonunuzun ne zaman çalışacağını belirleyen tetikleyicidir. HTTP Trigger, adından da anlaşılacağı gibi, bir HTTP isteği geldiğinde fonksiyonunuzu ayağa kaldırır. Klasik bir web sunucusu veya API gateway kurmanıza gerek kalmadan, doğrudan kod yazıp deploy edebiliyorsunuz.
Bir sysadmin olarak bunu şöyle düşünebilirsiniz: Eskiden bir webhook almak için Nginx kurardınız, uygulama deploy ederdiniz, process manager ayarlardınız, SSL sertifikası bağlardınız. Şimdi sadece bir fonksiyon yazıp “git” diyorsunuz. Ölçekleme, yüksek erişilebilirlik, SSL, bunların hepsi Azure’un sorunu haline geliyor.
Geliştirme Ortamını Kurmak
Başlamadan önce local geliştirme ortamınızı hazırlamanız gerekiyor. Azure Functions Core Tools ve Azure CLI olmadan bu işlerin içinden çıkmak çok zorlaşıyor.
# Azure Functions Core Tools kurulumu (Ubuntu/Debian)
curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg
sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-$(lsb_release -cs)-prod $(lsb_release -cs) main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-get update
sudo apt-get install azure-functions-core-tools-4
# Azure CLI kurulumu
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Kurulumu doğrula
func --version
az --version
Node.js ile çalışacaksanız npm üzerinden de kurabilirsiniz:
# npm ile kurulum
npm install -g azure-functions-core-tools@4 --unsafe-perm true
# Python sanal ortamı oluşturma (Python fonksiyonları için)
python3 -m venv .venv
source .venv/bin/activate
pip install azure-functions
İlk HTTP Trigger Fonksiyonunu Oluşturmak
Azure’a giriş yapıp yeni bir Functions projesi oluşturalım:
# Azure'a giriş
az login
# Resource group oluştur
az group create
--name rg-functions-demo
--location westeurope
# Storage account oluştur (Functions için zorunlu)
az storage account create
--name stfunctionsdemo2024
--resource-group rg-functions-demo
--location westeurope
--sku Standard_LRS
# Function App oluştur (Python runtime ile)
az functionapp create
--resource-group rg-functions-demo
--consumption-plan-location westeurope
--runtime python
--runtime-version 3.11
--functions-version 4
--name func-demo-httpapi
--storage-account stfunctionsdemo2024
Şimdi local’de proje iskeletini oluşturalım:
# Yeni Functions projesi başlat
func init MyHttpApi --python
cd MyHttpApi
# HTTP Trigger fonksiyonu ekle
func new --name ProcessWebhook --template "HTTP trigger" --authlevel "function"
Bu komuttan sonra ProcessWebhook adında bir klasör oluşur ve içinde __init__.py ile function.json dosyaları bulunur.
function.json Yapılandırması
function.json dosyası, fonksiyonunuzun davranışını tanımladığınız yerdir. HTTP Trigger için bu dosya kritik öneme sahip:
cat ProcessWebhook/function.json
Varsayılan içerik şöyle görünür ve bunu ihtiyaçlarınıza göre düzenleyebilirsiniz:
# function.json içeriği - bu bir JSON dosyasıdır
# Aşağıdaki yapıyı ProcessWebhook/function.json dosyasına yazın:
cat > ProcessWebhook/function.json << 'EOF'
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": ["get", "post"],
"route": "webhook/process"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
EOF
authLevel değerleri ve anlamları:
- anonymous: Herkes erişebilir, key gerekmez
- function: Fonksiyon bazlı API key gerektirir
- admin: Master key gerektirir, yönetim işlemleri için
methods dizisindeki değerler:
- get: GET isteklerini kabul eder
- post: POST isteklerini kabul eder
- put: PUT isteklerini kabul eder
- delete: DELETE isteklerini kabul eder
- patch: PATCH isteklerini kabul eder
route parametresi ile varsayılan URL yapısını değiştirebilirsiniz. Belirtmezseniz URL api/FonksiyonAdi şeklinde olur.
Gerçek Dünya Senaryosu: GitHub Webhook İşleyici
Bir CI/CD pipeline’ınız var ve GitHub’dan gelen webhook’ları işlemek istiyorsunuz. Her push event’inde Slack’e bildirim göndermek, log kayıt tutmak ve gerektiğinde deployment tetiklemek istiyorsunuz.
# requirements.txt dosyasını güncelle
cat > requirements.txt << 'EOF'
azure-functions
requests
hmac
hashlib
EOF
# ProcessWebhook/__init__.py içeriği
cat > ProcessWebhook/__init__.py << 'PYEOF'
import azure.functions as func
import json
import hmac
import hashlib
import requests
import logging
import os
def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info("GitHub webhook alındı, işleniyor...")
# HMAC doğrulama - GitHub secret ile imzayı kontrol et
github_secret = os.environ.get("GITHUB_WEBHOOK_SECRET", "")
signature_header = req.headers.get("X-Hub-Signature-256", "")
body = req.get_body()
if github_secret and signature_header:
expected_sig = "sha256=" + hmac.new(
github_secret.encode(),
body,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected_sig, signature_header):
logging.warning("Geçersiz webhook imzası!")
return func.HttpResponse(
json.dumps({"error": "Unauthorized"}),
status_code=401,
mimetype="application/json"
)
# Event tipini belirle
event_type = req.headers.get("X-GitHub-Event", "unknown")
try:
payload = req.get_json()
except ValueError:
return func.HttpResponse(
json.dumps({"error": "Invalid JSON payload"}),
status_code=400,
mimetype="application/json"
)
# Push event işleme
if event_type == "push":
repo_name = payload.get("repository", {}).get("full_name", "unknown")
pusher = payload.get("pusher", {}).get("name", "unknown")
branch = payload.get("ref", "").replace("refs/heads/", "")
commits = payload.get("commits", [])
message = f"*Yeni Push!* {repo_name}nBranch: {branch}nKim: {pusher}nCommit sayısı: {len(commits)}"
# Slack bildirimi gönder
slack_webhook = os.environ.get("SLACK_WEBHOOK_URL", "")
if slack_webhook:
requests.post(slack_webhook, json={"text": message}, timeout=10)
logging.info(f"Push event işlendi: {repo_name}/{branch}")
return func.HttpResponse(
json.dumps({"status": "success", "processed": event_type}),
status_code=200,
mimetype="application/json"
)
return func.HttpResponse(
json.dumps({"status": "ignored", "event": event_type}),
status_code=200,
mimetype="application/json"
)
PYEOF
Environment Variable ve Application Settings Yönetimi
Local geliştirmede local.settings.json kullanırken, production’da Azure Portal veya CLI üzerinden Application Settings tanımlarsınız.
# local.settings.json yapılandırması
cat > local.settings.json << 'EOF'
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "python",
"GITHUB_WEBHOOK_SECRET": "supersecretkey123",
"SLACK_WEBHOOK_URL": "https://hooks.slack.com/services/xxx/yyy/zzz"
}
}
EOF
# Production'a settings ekle (CLI ile)
az functionapp config appsettings set
--name func-demo-httpapi
--resource-group rg-functions-demo
--settings
"GITHUB_WEBHOOK_SECRET=supersecretkey123"
"SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/yyy/zzz"
# Mevcut settings'leri listele
az functionapp config appsettings list
--name func-demo-httpapi
--resource-group rg-functions-demo
--output table
Önemli not: local.settings.json dosyasını asla Git’e commit etmeyin. .gitignore dosyanıza ekleyin.
CORS Yapılandırması
Frontend uygulamanız farklı bir domain’den bu API’yi çağıracaksa CORS ayarlarını yapmanız gerekiyor:
# CORS ayarlarını yapılandır
az functionapp cors add
--name func-demo-httpapi
--resource-group rg-functions-demo
--allowed-origins "https://myapp.azurewebsites.net" "https://www.mycompany.com"
# Mevcut CORS ayarlarını gör
az functionapp cors show
--name func-demo-httpapi
--resource-group rg-functions-demo
# Development için tüm origin'lere izin ver (sadece test ortamı!)
az functionapp cors add
--name func-demo-httpapi
--resource-group rg-functions-demo
--allowed-origins "*"
Local geliştirmede CORS’u test etmek için local.settings.json‘a şunu ekleyebilirsiniz:
# local.settings.json'a CORS host ekle
az functionapp cors add
--name func-demo-httpapi
--resource-group rg-functions-demo
--allowed-origins "http://localhost:3000"
Fonksiyonu Deploy Etmek ve Test Etmek
# Local'de çalıştır ve test et
func start
# Başka bir terminalde test isteği gönder
curl -X POST http://localhost:7071/api/webhook/process
-H "Content-Type: application/json"
-H "X-GitHub-Event: push"
-d '{"repository": {"full_name": "myorg/myrepo"}, "pusher": {"name": "ahmet"}, "ref": "refs/heads/main", "commits": [{"id": "abc123"}]}'
# Azure'a deploy et
func azure functionapp publish func-demo-httpapi
# Deploy sonrası fonksiyon URL'ini al
az functionapp function show
--name func-demo-httpapi
--resource-group rg-functions-demo
--function-name ProcessWebhook
--query "invokeUrlTemplate"
--output tsv
# Fonksiyon key'ini al
az functionapp keys list
--name func-demo-httpapi
--resource-group rg-functions-demo
Gerçek Dünya Senaryosu 2: REST API Endpoint Zincirleme
Daha karmaşık bir senaryo: Bir e-ticaret sisteminde sipariş alındığında stok kontrolü, ödeme doğrulama ve bildirim gönderme işlemlerini sırayla yapan bir HTTP Trigger.
# OrderProcessor/__init__.py
cat > OrderProcessor/__init__.py << 'PYEOF'
import azure.functions as func
import json
import logging
import os
import requests
from datetime import datetime
def validate_order(order_data: dict) -> tuple:
"""Sipariş verilerini doğrula"""
required_fields = ["product_id", "quantity", "customer_email", "payment_token"]
for field in required_fields:
if field not in order_data:
return False, f"Eksik alan: {field}"
if order_data["quantity"] <= 0:
return False, "Miktar sıfırdan büyük olmalı"
return True, "OK"
def check_stock(product_id: str, quantity: int) -> bool:
"""Stok API'sini kontrol et"""
stock_api = os.environ.get("STOCK_API_URL", "")
if not stock_api:
logging.warning("STOCK_API_URL tanımlı değil, stok kontrolü atlandı")
return True
try:
response = requests.get(
f"{stock_api}/check/{product_id}",
params={"quantity": quantity},
timeout=5
)
return response.json().get("available", False)
except requests.RequestException as e:
logging.error(f"Stok kontrolü başarısız: {e}")
return False
def main(req: func.HttpRequest) -> func.HttpResponse:
# Sadece POST kabul et
if req.method != "POST":
return func.HttpResponse(
json.dumps({"error": "Sadece POST metodu kabul edilir"}),
status_code=405,
mimetype="application/json",
headers={"Allow": "POST"}
)
try:
order_data = req.get_json()
except ValueError:
return func.HttpResponse(
json.dumps({"error": "Geçersiz JSON formatı"}),
status_code=400,
mimetype="application/json"
)
# Sipariş doğrulama
is_valid, message = validate_order(order_data)
if not is_valid:
return func.HttpResponse(
json.dumps({"error": message, "status": "validation_failed"}),
status_code=422,
mimetype="application/json"
)
# Stok kontrolü
if not check_stock(order_data["product_id"], order_data["quantity"]):
return func.HttpResponse(
json.dumps({"error": "Yetersiz stok", "status": "out_of_stock"}),
status_code=409,
mimetype="application/json"
)
# Sipariş ID oluştur
order_id = f"ORD-{datetime.utcnow().strftime('%Y%m%d%H%M%S')}-{order_data['product_id'][:4].upper()}"
logging.info(f"Sipariş oluşturuldu: {order_id}")
return func.HttpResponse(
json.dumps({
"status": "success",
"order_id": order_id,
"message": "Siparişiniz alındı",
"estimated_delivery": "3-5 iş günü"
}),
status_code=201,
mimetype="application/json"
)
PYEOF
Monitoring ve Logging
Azure Functions’ta Application Insights entegrasyonu monitoring açısından çok değerli. Kurulum ve temel sorguları ele alalım:
# Application Insights oluştur
az monitor app-insights component create
--app func-demo-insights
--location westeurope
--resource-group rg-functions-demo
--application-type web
# Instrumentation key al
INSTRUMENTATION_KEY=$(az monitor app-insights component show
--app func-demo-insights
--resource-group rg-functions-demo
--query "instrumentationKey"
--output tsv)
# Function App'e bağla
az functionapp config appsettings set
--name func-demo-httpapi
--resource-group rg-functions-demo
--settings "APPINSIGHTS_INSTRUMENTATIONKEY=$INSTRUMENTATION_KEY"
# Fonksiyon loglarını canlı izle
func azure functionapp logstream func-demo-httpapi
# Az CLI ile son execution'ları listele
az monitor app-insights query
--app func-demo-insights
--resource-group rg-functions-demo
--analytics-query "requests | where timestamp > ago(1h) | order by timestamp desc | take 20"
Güvenlik: IP Kısıtlama ve API Key Yönetimi
Production ortamında güvenliği sıkılaştırmak için birkaç katmanlı yaklaşım kullanmalısınız:
# Belirli IP'lere erişim kısıtlama
az functionapp config access-restriction add
--name func-demo-httpapi
--resource-group rg-functions-demo
--rule-name "OfficeNetwork"
--action Allow
--ip-address 203.0.113.0/24
--priority 100
# GitHub webhook IP aralıklarını ekle
az functionapp config access-restriction add
--name func-demo-httpapi
--resource-group rg-functions-demo
--rule-name "GitHubWebhooks"
--action Allow
--ip-address 192.30.252.0/22
--priority 200
# Kısıtlamaları listele
az functionapp config access-restriction show
--name func-demo-httpapi
--resource-group rg-functions-demo
# Yeni host key oluştur (API key rotasyonu için)
az functionapp keys set
--name func-demo-httpapi
--resource-group rg-functions-demo
--key-name "partner-integration-key"
--key-type functionKeys
--function-name ProcessWebhook
# Eski key'i sil
az functionapp keys delete
--name func-demo-httpapi
--resource-group rg-functions-demo
--key-name "old-partner-key"
--key-type functionKeys
--function-name ProcessWebhook
Yaygın Sorunlar ve Çözümleri
Gerçek ortamlarda sıkça karşılaşılan sorunları ve çözüm yollarını ele alalım.
Cold Start problemi: Consumption plan kullandığınızda, uzun süre istek gelmezse fonksiyon uyku moduna geçer. İlk istek geldiğinde başlatma süresi 2-5 saniyeye kadar çıkabilir.
Çözüm için Premium plan veya “Always On” özelliği olan bir plan kullanabilirsiniz:
# Premium plana geçiş
az functionapp update
--name func-demo-httpapi
--resource-group rg-functions-demo
--set siteConfig.alwaysOn=true
# Minimum instance sayısını ayarla (Premium plan)
az functionapp config set
--name func-demo-httpapi
--resource-group rg-functions-demo
--minimum-elastic-instance-count 1
Timeout ayarları: Varsayılan timeout Consumption plan’da 5 dakika, Premium’da 30 dakikadır. host.json ile değiştirebilirsiniz:
cat > host.json << 'EOF'
{
"version": "2.0",
"functionTimeout": "00:10:00",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"maxTelemetryItemsPerSecond": 20
}
}
},
"extensions": {
"http": {
"routePrefix": "api",
"maxOutstandingRequests": 200,
"maxConcurrentRequests": 100,
"dynamicThrottlesEnabled": true
}
}
}
EOF
Rate limiting: maxOutstandingRequests ve maxConcurrentRequests parametreleri ile fonksiyonunuza gelen istek yükünü kontrol edebilirsiniz. Aşıldığında Azure otomatik olarak 429 döner.
Sonuç
Azure Functions HTTP Trigger, doğru yapılandırıldığında inanılmaz derecede güçlü ve esnek bir araç. Bu yazıda ele aldığımız konuları özetlemek gerekirse:
- Geliştirme ortamı kurulumu ve Core Tools kullanımı production kalitesinde iş yapmanın temelidir
function.jsoniçindekiauthLevelverouteparametrelerini iş gereksinimlerinize göre dikkatli şekilde ayarlayın- Environment variable’ları asla koda gömmeyín, Application Settings kullanın
- CORS, IP kısıtlama ve API key yönetimini birlikte kullanarak katmanlı güvenlik oluşturun
- Application Insights entegrasyonunu en başından kurun, sonradan “keşke takip etseydim” dememeniz için
- Cold start sorununu göz ardı etmeyin, SLA gereksinimlerinize göre plan seçimini yapın
host.jsonüzerinden concurrency ve timeout ayarlarını üretim trafiğinize göre optimize edin
Serverless geçişin en büyük tuzağı, “sadece kod yazıyoruz, altyapı yok” yanılgısına düşmektir. Altyapı var, sadece soyutlanmış. Bu soyutlamanın altında ne olduğunu anlayan sysadmin, hem daha sağlam sistemler kurar hem de sorunlar çıktığında çok daha hızlı çözer. Azure Functions HTTP Trigger için söylenen her şey bu ilke etrafında şekilleniyor.
