
![]()
Claude Code ile FastAPI üzerine çalışırken ilginç bir şeyle karşılaştım. Kod dosyamda @app.middleware("http") şeklinde bir decorator gördüm ve düşündüm: “Durun bir dakika, ben hep @app.get("/"), @app.post("/") gibi decorator’lar görüyordum. Bu @app.middleware("http") ne işe yarıyor?”
Soruyu sorduğumda aldığım cevap beni şaşırttı – bu decorator her HTTP isteğinde (request) çalışıyormuş, sadece belirli bir endpoint’te değil! Konuyu biraz araştırdım ve öğrendiklerimi sizlerle paylaşıyorum.
Decorator’lar Arasındaki Kritik Fark
Öncelikle şu temel farkı anlayalım: FastAPI’de kullandığımız decorator’lar aslında iki farklı amaca hizmet ediyor.
Standart Route Decorator’ları
Standart route decorator’ları (@app.get(), @app.post()) sadece belirli bir HTTP metoduna ve belirli bir path’e gelen istekleri işler [1]. Örneğin:
@app.get("/")
async def root():
return {"message": "Hello World"}
Bu kod sadece root path’e (/) gelen GET isteklerinde çalışır. Başka bir path’e istek gelirse bu fonksiyon hiç çalışmaz.
Middleware Decorator’ı
Middleware decorator’ı (@app.middleware("http")) ise tamamen farklı çalışır – uygulamanıza gelen her HTTP isteğinde, hangi path veya metod olursa olsun çalışır [1].
@app.middleware("http")
async def log_all_requests(request: Request, call_next):
print(f"Gelen istek: {request.url}")
response = await call_next(request)
return response
Bu middleware tüm isteklerinizi yakalar – /, /users, /api/products, hatta var olmayan path’ler bile!
| Özellik | Route Decorator | Middleware Decorator |
|---|---|---|
| Çalışma Zamanı | Sadece belirli path’te | Her HTTP isteğinde |
| HTTP Metodu | Belirli (GET, POST vb.) | Tümü |
| Kullanım Amacı | Endpoint mantığı | Ortak işlemler |
| Çalışma Sırası | Middleware’den sonra | Route’lardan önce |
Middleware Nedir ve Nasıl Çalışır?
Middleware (ara yazılım), gelen HTTP isteği ile uygulamanızın işleme mantığı arasında yer alan bir katmandır [13]. Bunu havalimanı güvenliğine benzetebiliriz: her yolcu (istek) uçağa binmeden önce güvenlikten geçmek zorundadır, sonra uçaktan inerken de yine güvenlik kontrolleri yapılır [13].
Request-Response Yaşam Döngüsü (Lifecycle)
FastAPI’de bir istek şu adımlardan geçer [1]:
- İstek Gelir → İstemciden (client) bir HTTP isteği gelir
- Middleware Başlar → Middleware fonksiyonu çalışmaya başlar
- İstek İşlenir →
call_next(request)çağrılır ve istek route handler’a gider - Route Handler Çalışır → Endpoint fonksiyonunuz çalışır
- Response Oluşur → Endpoint bir response döner
- Middleware Devam Eder → Middleware kaldığı yerden devam eder
- Response Döner → Son response istemciye gönderilir
Middleware fonksiyonunuz hem istek işlenmeden önce hem de response dönmeden önce kod çalıştırabilir [1].
call_next() Fonksiyonu Nedir?
call_next() fonksiyonu, isteğin pipeline’da (işlem hattında) bir sonraki adıma geçmesini sağlar [6]. Bu bir sonraki adım başka bir middleware olabilir veya doğrudan route handler olabilir.
@app.middleware("http")
async def my_middleware(request: Request, call_next):
# call_next() öncesi: İstek işlenmeden ÖNCE çalışır
print("İstek alındı")
# İsteği bir sonraki adıma gönder ve response'u bekle
response = await call_next(request)
# call_next() sonrası: Response dönmeden ÖNCE çalışır
print("Response hazırlandı")
return response
İlk Middleware Örneğimiz: Response Time Ölçümü
Hadi birlikte ilk middleware’imizi yazalım. Bu örnek her isteğin ne kadar sürede işlendiğini ölçecek ve bunu response header’ına ekleyecek [1].
import time
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
# Başlangıç zamanını kaydet
start_time = time.perf_counter()
# İsteği işle ve response'u al
response = await call_next(request)
# İşlem süresini hesapla
process_time = time.perf_counter() - start_time
# Response header'ına ekle
response.headers["X-Process-Time"] = str(process_time)
return response
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get("/slow")
async def slow_endpoint():
time.sleep(2) # 2 saniye bekle
return {"message": "Bu yavaş bir endpoint"}
Bu örnekte time.perf_counter() kullandık çünkü bu metod bu tür hassas ölçümler için daha uygundur [1].
Şimdi bu uygulamayı çalıştırıp / veya /slow endpoint’lerine istek attığınızda, response header’larında X-Process-Time değerini göreceksiniz. Bu her endpoint için ne kadar süre harcandığını gösterir.
Dikkat: Özel header’lar eklerken X- prefix’i kullanmak yaygın bir uygulamadır [1].
Gerçek Dünya Kullanım Senaryoları
Şimdi middleware’in gerçek projelerde nasıl kullanıldığını görelim. Birlikte 4 farklı senaryo üzerinde çalışacağız.
1. Request Logging (İstek Kayıt Sistemi)
Logging, uygulama geliştirmede kritik bir debugging ve monitoring aracıdır [14]. Her gelen isteği kaydetmek için middleware kullanabiliriz [17]:
import logging
from fastapi import FastAPI, Request
from datetime import datetime
# Logger yapılandırması
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI()
@app.middleware("http")
async def log_requests(request: Request, call_next):
# İstek bilgilerini logla
logger.info(f"[{datetime.now()}] {request.method} {request.url}")
logger.info(f"İstemci IP: {request.client.host}")
# İsteği işle
response = await call_next(request)
# Response durumunu logla
logger.info(f"Status Code: {response.status_code}")
return response
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"user_id": user_id, "name": "Ahmet"}
Bu middleware sayesinde konsolunuzda şöyle loglar göreceksiniz:
INFO: [2025-10-25 10:30:45] GET http://localhost:8000/users/123 INFO: İstemci IP: 127.0.0.1 INFO: Status Code: 200
2. Authentication Middleware (Kimlik Doğrulama)
Kimlik doğrulama işlemleri middleware’in en yaygın kullanım alanlarından biridir [9]. Token kontrolü yapan bir middleware yazalım [17]:
from fastapi import FastAPI, Request, HTTPException
from typing import Callable
app = FastAPI()
# Güvenli endpoint'ler listesi
SECURE_PATHS = ["/admin", "/dashboard", "/api/private"]
@app.middleware("http")
async def auth_middleware(request: Request, call_next: Callable):
# Path güvenli mi kontrol et
path = request.url.path
if any(path.startswith(secure_path) for secure_path in SECURE_PATHS):
# Authorization header var mı?
auth_header = request.headers.get("Authorization")
if not auth_header:
raise HTTPException(
status_code=401,
detail="Authorization header eksik"
)
# Token geçerli mi? (basit kontrol)
if not auth_header.startswith("Bearer "):
raise HTTPException(
status_code=401,
detail="Geçersiz token formatı"
)
token = auth_header.replace("Bearer ", "")
# Gerçek uygulamada burada token doğrulama yapılır
if token != "secret-token-123":
raise HTTPException(
status_code=403,
detail="Geçersiz token"
)
# Her şey yolunda, devam et
response = await call_next(request)
return response
@app.get("/")
async def public_endpoint():
return {"message": "Bu herkese açık"}
@app.get("/admin/users")
async def admin_endpoint():
return {"message": "Bu sadece admin'lere açık"}
Bu middleware ile /admin altındaki tüm endpoint’ler otomatik olarak korunur.
3. Custom Header Ekleme
Her response’a özel header’lar eklemek, API versiyonu veya server bilgisi gibi metadata paylaşmak için kullanılır [2]:
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware("http")
async def add_custom_headers(request: Request, call_next):
response = await call_next(request)
# Özel header'lar ekle
response.headers["X-API-Version"] = "1.0.0"
response.headers["X-Server-Name"] = "FastAPI-Production"
response.headers["X-Request-ID"] = str(id(request)) # Unique ID
return response
@app.get("/products")
async def get_products():
return [
{"id": 1, "name": "Laptop"},
{"id": 2, "name": "Mouse"}
]
Artık her response şu header’ları içerecek:
X-API-Version: 1.0.0 X-Server-Name: FastAPI-Production X-Request-ID: 140234567890123
4. CORS (Cross-Origin Resource Sharing) Yönetimi
CORS, web uygulamalarında farklı origin’lerden gelen istekleri yönetmek için kullanılır [11]. FastAPI, CORSMiddleware adında yerleşik bir middleware sunar [2]:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# CORS middleware'i ekle
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000", "https://myapp.com"],
allow_credentials=True,
allow_methods=["*"], # Tüm HTTP metodları
allow_headers=["*"], # Tüm header'lar
)
@app.get("/api/data")
async def get_data():
return {"data": "Bu cross-origin isteklere açık"}
Önemli Not: Development ortamında allow_origins=[“*”] kullanabilirsiniz ancak production’da mutlaka belirli origin’leri belirtmelisiniz [2].
5. Rate Limiting (İstek Sınırlama)
Rate limiting, API’nizin kötüye kullanımını önlemek için IP başına istek sayısını sınırlar [14][15]. Basit bir rate limiter yazalım:
from fastapi import FastAPI, Request, HTTPException
from collections import defaultdict
from datetime import datetime, timedelta
app = FastAPI()
# IP başına istek sayacı
request_counts = defaultdict(lambda: {"count": 0, "reset_time": datetime.now()})
# Dakika başına maksimum 10 istek
MAX_REQUESTS = 10
TIME_WINDOW = timedelta(minutes=1)
@app.middleware("http")
async def rate_limit_middleware(request: Request, call_next):
client_ip = request.client.host
current_time = datetime.now()
# IP'nin geçmiş isteklerini kontrol et
client_data = request_counts[client_ip]
# Zaman penceresi dolmuş mu?
if current_time > client_data["reset_time"]:
# Sayacı sıfırla
client_data["count"] = 0
client_data["reset_time"] = current_time + TIME_WINDOW
# İstek limitini aştı mı?
if client_data["count"] >= MAX_REQUESTS:
raise HTTPException(
status_code=429,
detail="Çok fazla istek gönderdiniz. Lütfen bekleyin."
)
# İstek sayısını artır
client_data["count"] += 1
# İsteği işle
response = await call_next(request)
# Response header'larına limit bilgilerini ekle
response.headers["X-RateLimit-Limit"] = str(MAX_REQUESTS)
response.headers["X-RateLimit-Remaining"] = str(
MAX_REQUESTS - client_data["count"]
)
return response
@app.get("/api/search")
async def search(query: str):
return {"query": query, "results": []}
Bu middleware, her IP adresinden dakikada maksimum 10 istek kabul eder. Limit aşıldığında 429 (Too Many Requests) hatası döner.
Middleware’i Ne Zaman Kullanmalıyız?
Middleware kullanımı için ideal senaryolar:
✅ Kullan:
- Cross-Cutting Concerns (Kesişen Kaygılar): Logging, authentication, metrics gibi tüm endpoint’leri ilgilendiren işlemler [12]
- Request/Response Modifikasyonu: Her istekte veya response’da yapılması gereken değişiklikler [6]
- Performans Monitoring: İstek sürelerini ölçme, metrics toplama [14][15]
- Güvenlik: Rate limiting, IP filtering, token validation [20]
- Header Yönetimi: CORS, custom header’lar, security header’ları [11]
❌ Kullanma:
- Endpoint-Specific Logic: Sadece belirli bir endpoint’e özel mantık (bunun için route decorator kullan) [12]
- Heavy Processing: Middleware’deki ağır işlemler tüm uygulamanızı yavaşlatır [10]
- Business Logic: İş mantığı route handler’larda olmalı, middleware’de değil [6]
- Dependency Injection Gerektiren Durumlar: FastAPI’nin dependency sistemi daha uygun olabilir [4]
Middleware Çalışma Sırası (Execution Order)
Birden fazla middleware eklerken, son eklenen middleware en dıştadır ve ilk çalışır [1]. Bunu şöyle düşünebiliriz:
app = FastAPI()
@app.middleware("http")
async def first_middleware(request: Request, call_next):
print("1. Middleware başladı")
response = await call_next(request)
print("1. Middleware bitti")
return response
@app.middleware("http")
async def second_middleware(request: Request, call_next):
print("2. Middleware başladı")
response = await call_next(request)
print("2. Middleware bitti")
return response
@app.get("/test")
async def test():
print("Route handler çalışıyor")
return {"message": "test"}
İstek geldiğinde çıktı:
2. Middleware başladı 1. Middleware başladı Route handler çalışıyor 1. Middleware bitti 2. Middleware bitti
Son eklenen middleware ilk çalışır (soğan katmanları gibi) [1].
Best Practices (En İyi Uygulamalar)
- Async Kullanın: Middleware fonksiyonlarınızı async def olarak tanımlayın [1]
- Hata Yönetimi: Middleware’de exception handling yapın [6]
- Performans: Middleware’de minimum işlem yapın [10]
- Logging: Detaylı loglar tutun ama performansı düşürmeyin [14]
- Testing: Middleware’lerinizi mutlaka test edin [6]
- Documentation: Middleware’in ne yaptığını dokümante edin [12]
# ✅ İyi örnek
@app.middleware("http")
async def good_middleware(request: Request, call_next):
try:
# Hızlı işlemler yap
start = time.perf_counter()
response = await call_next(request)
duration = time.perf_counter() - start
# Sadece gerekli header'ı ekle
response.headers["X-Time"] = str(duration)
return response
except Exception as e:
logger.error(f"Middleware hatası: {e}")
raise
# ❌ Kötü örnek
@app.middleware("http")
def bad_middleware(request: Request, call_next): # async değil!
# Ağır database sorgusu (middleware'de yapma!)
result = heavy_database_query()
# Senkron çağrı (yavaşlatır!)
response = call_next(request)
return response
Middleware vs Dependency Injection
FastAPI’de dependency injection sistemi de var. Peki ne zaman middleware, ne zaman dependency kullanmalıyız [4]?
Middleware kullan:
- Tüm endpoint’leri etkileyen global işlemler
- Request/response lifecycle’ını tamamen kontrol etmek
Dependency kullan:
- Sadece belirli endpoint’lerin ihtiyaç duyduğu işlemler
- Database connection, user authentication gibi paylaşılan kaynaklar
- Test edilebilirliği önemli olan yerler
Sonuç ve Özet
Bu yazıda FastAPI middleware konusunu ele aldık! Özetle;
✅ @app.middleware("http") her HTTP isteğinde çalışır
✅ Middleware request-response lifecycle’ında kritik rol oynar
✅ call_next() ile pipeline kontrolü sağlarız
✅ Logging, authentication, rate limiting gibi gerçek dünya problemlerini çözer
✅ Best practices’leri uygulayarak performanslı middleware yazabiliriz
Middleware, FastAPI uygulamalarınızı daha güvenli, izlenebilir ve yönetilebilir hale getirir. Doğru kullanıldığında, middleware uygulamanızın esnekliğini ve yeniden kullanılabilirliğini önemli ölçüde artırır [12].
Bundan sonra neler deneyebilirsiniz?
- Kendi FastAPI projenizde basit bir logging middleware yazın
- Response time ölçümü yapan middleware’i test edin
- Authentication middleware’i kendi güvenlik ihtiyaçlarınıza göre uyarlayın
- Middleware stack’i deneyin – birden fazla middleware ekleyin ve sıralamasını gözlemleyin
Kaynaklar
[1] FastAPI Official Documentation – Middleware. https://fastapi.tiangolo.com/tutorial/middleware/
[2] Orchestra – FastAPI Middleware: A Comprehensive Guide. https://www.getorchestra.io/guides/fastapi-middleware-a-comprehensive-guide
[3] TutorialsPoint – FastAPI Middleware. https://www.tutorialspoint.com/fastapi/fastapi_middleware.htm
[4] Stack Overflow – How to write a custom FastAPI middleware class. https://stackoverflow.com/questions/71525132/how-to-write-a-custom-fastapi-middleware-class
[5] Medium – FastAPI: Experiment Middleware feature. https://medium.com/@life-is-short-so-enjoy-it/fastapi-experiment-middleware-feature-c0a0c7314d74
[6] Semaphore – Building Custom Middleware in FastAPI. https://semaphore.io/blog/custom-middleware-fastapi
[7] DEV Community – Creating Middlewares in FastAPI: A Step-by-Step Guide. https://dev.to/aakashkhanna/creating-middlewares-in-fastapi-a-step-by-step-guide-1b4m
[8] Medium – Middleware in FastAPI: From Basic Implementation to Route-Based Strategies. https://medium.com/@saveriomazza/mastering-middleware-in-fastapi-from-basic-implementation-to-route-based-strategies-d62eff6b5463
[9] Orchestra – FastAPI Advanced Middleware Tutorial. https://www.getorchestra.io/guides/fastapi-advanced-middleware-tutorial
[10] Sentry – Write a custom FastAPI middleware class. https://sentry.io/answers/write-a-custom-fastapi-middleware-class/
[11] FastAPI Official Documentation – Advanced Middleware. https://fastapi.tiangolo.com/advanced/middleware/
[12] Semaphore – Custom Middleware Benefits and Use Cases. https://semaphore.io/blog/custom-middleware-fastapi
[13] Medium – Understanding When and How to Implement FastAPI Middleware. https://medium.com/data-science/understanding-when-and-how-to-implement-fastapi-middleware-examples-and-use-cases-c2bd37cb4ffe
[14] Towards Data Science – FastAPI Middleware Examples and Use Cases. https://towardsdatascience.com/understanding-when-and-how-to-implement-fastapi-middleware-examples-and-use-cases-c2bd37cb4ffe/
[15] Mike Huls – FastAPI Middleware Implementation. https://mikehuls.com/fastapi-middleware/
[16] Medium – FastAPI Middleware Experimentation. https://medium.com/@life-is-short-so-enjoy-it/fastapi-experiment-middleware-feature-c0a0c7314d74
[17] Stackademic – Middleware in FastAPI: Request and Response Handling. https://blog.stackademic.com/middleware-in-fastapi-how-to-create-and-use-middleware-to-handle-requests-and-responses-4637b614d1bd
[18] TutorialsPoint – FastAPI Middleware Documentation. https://www.tutorialspoint.com/fastapi/fastapi_middleware.htm
[19] Medium – Mastering Middleware in FastAPI. https://medium.com/@saveriomazza/mastering-middleware-in-fastapi-from-basic-implementation-to-route-based-strategies-d62eff6b5463
[20] Codepunk – Setting Up Middleware in FastAPI. https://www.oneloop.ai/blog/setting-up-middleware-in-fastapi