Takip et

FastAPI ve İlişkisel Veritabanı Kullanımı (Ubuntu Üzerinde)

FastAPI ve İlişkisel Veritabanı Kullanımı (Ubuntu Üzerinde) Modern web uygulamaları geliştirirken, hızlı ve etkili API’lar oluşturmak krit

FastAPI ve İlişkisel Veritabanı Kullanımı (Ubuntu Üzerinde)

Modern web uygulamaları geliştirirken, hızlı ve etkili API’lar oluşturmak kritik öneme sahiptir. Python ekosisteminde son yıllarda popülerliği hızla artan FastAPI, yüksek performanslı, asenkron ve kullanımı kolay bir web çatısı olarak öne çıkmaktadır. İlişkisel veritabanları ise, veri tutarlılığı, yapısal bütünlük ve güçlü sorgu yetenekleri sayesinde birçok uygulamanın belkemiğini oluşturur. Bu makale, Ubuntu işletim sistemi üzerinde FastAPI’yi bir ilişkisel veritabanı (PostgreSQL örneği üzerinden) ile nasıl entegre edeceğinizi, SQLAlchemy ORM’i kullanarak veri modellerinizi nasıl yöneteceğinizi ve Pydantic ile veri doğrulamasını nasıl yapacağınızı ayrıntılı bir şekilde ele alacaktır. Ayrıca, veritabanı şema değişikliklerini yönetmek için Alembic migrasyon aracını da inceleyeceğiz.

Bu rehber, hem FastAPI’ye yeni başlayanlar hem de mevcut projelerinde ilişkisel veritabanı entegrasyonu arayan deneyimli geliştiriciler için kapsamlı bir kaynak olmayı hedeflemektedir.

FastAPI ve İlişkisel Veritabanları Neden Birlikte Kullanılmalı?

FastAPI, Python’ın tip ipuçlarını (type hints) kullanarak otomatik dokümantasyon (OpenAPI/Swagger UI), veri doğrulama ve serileştirme gibi özellikleri kutudan çıktığı gibi sunar. Starlette ve Pydantic üzerine inşa edilmiş olması sayesinde hem performanslı hem de geliştirici dostudur. İlişkisel veritabanları ise, tablolar arası ilişkiler, ACID özellikleri (Atomicity, Consistency, Isolation, Durability) ve güçlü SQL sorgu yetenekleri ile karmaşık veri yapılarını yönetmek için idealdir.

FastAPI’nin asenkron yapısı, veritabanı işlemleri gibi I/O yoğun görevleri beklerken diğer işlemleri yürütmeye devam etmesini sağlayarak uygulamanın genel yanıt süresini iyileştirir. SQLAlchemy gibi bir ORM (Object-Relational Mapper) kullanarak, SQL sorgularını doğrudan yazmak yerine Python nesneleriyle çalışabilir, bu da kodun daha okunabilir, sürdürülebilir ve hataya daha az yatkın olmasını sağlar.

Bu kombinasyon, geliştiricilere hızlı prototipleme, güçlü veri yönetimi ve yüksek performanslı API’lar oluşturma imkanı sunar.

Ön Gereksinimler

Bu makaledeki adımları takip edebilmek için aşağıdaki ön gereksinimlere sahip olmanız gerekmektedir:

* Ubuntu İşletim Sistemi: Tercihen 20.04 LTS veya daha yeni bir sürüm.
* Python 3.8+: Ubuntu genellikle Python 3 ile gelir, ancak en son sürümün kurulu olduğundan emin olun.
* pip: Python paket yöneticisi.
* Temel Terminal Bilgisi: Komut satırı işlemlerine aşina olmak.
* Sanal Ortam Bilgisi (Önerilir): Proje bağımlılıklarını izole etmek için Python sanal ortamları kullanmak iyi bir pratiktir.

Ortam Kurulumu

Uygulamamızı geliştirmeye başlamadan önce gerekli araçları ve kütüphaneleri kurmamız gerekiyor. Bu bölümde, Python sanal ortamı oluşturmaktan, FastAPI ve veritabanı sürücülerini kurmaya kadar tüm adımları ele alacağız.

Python Sanal Ortamı Oluşturma

Her Python projesi için ayrı bir sanal ortam kullanmak, bağımlılık çakışmalarını önler ve projelerinizi düzenli tutar.

İlk olarak, projeniz için bir dizin oluşturun ve içine girin:

mkdir fastapidb_app
cd fastapidb_app

Şimdi bir sanal ortam oluşturalım ve etkinleştirelim:

python3 -m venv venv
source venv/bin/activate

Sanal ortam etkinleştirildiğinde, terminal istemcinizin başında (venv) gibi bir ifade görmelisiniz.

Gerekli Python Paketlerini Kurma

Şimdi projemiz için gerekli olan Python paketlerini kuralım:

* FastAPI: Web çatısı.
* Uvicorn: ASGI sunucusu, FastAPI uygulamasını çalıştırmak için kullanılır.
* SQLAlchemy: Python ORM (Object-Relational Mapper) kütüphanesi.
* psycopg2-binary: PostgreSQL veritabanı sürücüsü. (Eğer MySQL kullanacaksanız mysqlclient veya PyMySQL kurmalısınız.)
* Pydantic: Veri doğrulama ve ayarlar yönetimi için kullanılır (FastAPI’nin bir bağımlılığıdır ancak açıkça belirtmek faydalı olabilir).
* Alembic: Veritabanı migrasyon aracı.

pip install fastapi uvicorn sqlalchemy psycopg2-binary alembic pydantic

Bu komut, projenizin venv ortamına gerekli tüm kütüphaneleri yükleyecektir.

Veritabanı Kurulumu (PostgreSQL Örneği)

Uygulamamızın veri depolama katmanı olarak PostgreSQL’i kullanacağız. Ubuntu üzerinde PostgreSQL’i kurmak ve yapılandırmak oldukça basittir.

PostgreSQL Kurulumu

Ubuntu sisteminizde PostgreSQL’i kurmak için aşağıdaki komutları kullanın:

sudo apt update
sudo apt install postgresql postgresql-contrib

Kurulum tamamlandıktan sonra PostgreSQL servisi otomatik olarak başlayacaktır. Servisin durumunu kontrol etmek için:

systemctl status postgresql

Çıktıda active (exited) veya active (running) gibi bir durum görmelisiniz.

Veritabanı Kullanıcısı ve Veritabanı Oluşturma

Güvenlik ve izolasyon için, uygulamanız için özel bir veritabanı ve bir kullanıcı oluşturmak iyi bir pratiktir. PostgreSQL, postgres adında varsayılan bir yönetici kullanıcısıyla gelir. Bu kullanıcıya geçiş yaparak yeni veritabanımızı ve kullanıcımızı oluşturacağız.

sudo -i -u postgres

Şimdi PostgreSQL komut istemcisine girelim:

psql

PostgreSQL istemcisindeyken, yeni bir veritabanı ve kullanıcı oluşturalım. Kendi güvenli parolanızı kullanmayı unutmayın!

CREATE DATABASE fastapidb;
CREATE USER fastapiuser WITH PASSWORD 'your_strong_password';
GRANT ALL PRIVILEGES ON DATABASE fastapidb TO fastapiuser;

İşlemler tamamlandığında \q yazarak psql istemcisinden çıkın ve ardından exit yazarak postgres kullanıcısından kendi kullanıcınıza geri dönün.

\q
exit

Artık fastapidb adında bir veritabanımız ve fastapiuser adında bu veritabanına tam yetkili bir kullanıcımız var.

FastAPI Uygulama Yapısı ve Temel Bileşenler

Bir FastAPI uygulamasını geliştirirken, kodu modüler ve yönetilebilir tutmak için belirli bir dosya yapısı izlemek faydalıdır. İşte önerilen yapı:

Proje Dizini Oluşturma

Daha önce oluşturduğumuz fastapidb_app dizininin içinde olduğunuzdan emin olun. Eğer değilseniz:

cd fastapidb_app

Dosya Yapısı

Projemiz için aşağıdaki dosya yapısını kullanacağız:

fastapidb_app/
├── venv/
├── alembic/
├── alembic.ini
├── main.py
├── database.py
├── models.py
├── schemas.py
├── crud.py
├── requirements.txt

* main.py: FastAPI uygulamasının ana giriş noktası. API rotalarını ve bağımlılıklarını tanımlar.
* database.py: Veritabanı bağlantısını, oturum yönetimini ve SQLAlchemy Base sınıfını içerir.
* models.py: SQLAlchemy ORM modellerini tanımlar. Veritabanı tablolarının Python karşılıklarıdır.
* schemas.py: Pydantic modellerini tanımlar. API istek ve yanıtlarının veri yapılarını doğrular ve serileştirir.
* crud.py: Veritabanı CRUD (Create, Read, Update, Delete) işlemlerini gerçekleştiren fonksiyonları içerir. Bu, iş mantığını API rotalarından ayırır.
* alembic/: Alembic migrasyon dosyalarını barındıran dizin.
* alembic.ini: Alembic yapılandırma dosyası.
* requirements.txt: Proje bağımlılıklarını listeler (isteğe bağlı, ancak iyi bir pratiktir).

Şimdi bu dosyaların içeriklerini tek tek oluşturalım.

SQLAlchemy ile Veritabanı Bağlantısı ve Modeller

SQLAlchemy, Python’da ilişkisel veritabanlarıyla çalışmak için kullanılan güçlü bir ORM ve SQL araç takımıdır. Veritabanı tablolarınızı Python sınıfları olarak tanımlamanıza olanak tanır.

Veritabanı Bağlantı Ayarları (database.py)

Bu dosya, veritabanı bağlantı bilgilerini ve SQLAlchemy’nin veritabanıyla etkileşim kurmasını sağlayacak temel yapılandırmayı içerir.

# fastapidb_app/database.py

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import os

Ortam değişkenlerinden veritabanı URL'sini al, yoksa varsayılanı kullan

Güvenlik için gerçek uygulamalarda bu tür bilgileri doğrudan koda yazmaktan kaçının.

.env dosyası veya benzeri bir yöntemle yönetilmelidir.

SQLALCHEMY_DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://fastapiuser:your_strong_password@localhost/fastapidb")

SQLAlchemy motorunu oluştur.

connect_args={"check_same_thread": False} SQLite için gereklidir, PostgreSQL için değil.

Ancak asenkron veritabanı sürücüleri kullanıldığında farklı yaklaşımlar gerekebilir.

engine = create_engine( SQLALCHEMY_DATABASE_URL )

Her bir veritabanı oturumu için bir SessionLocal sınıfı oluştur.

Bu sınıfın örnekleri, veritabanı işlemleri için kullanılacak.

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Veritabanı modellerimiz için temel sınıfı oluştur.

Bu sınıf, tüm SQLAlchemy ORM modellerimizin miras alacağı temel sınıftır.

Base = declarative_base()

FastAPI bağımlılık enjeksiyonu için veritabanı oturumu sağlayan bir yardımcı fonksiyon.

def get_db(): db = SessionLocal() try: yield db finally: db.close()

Açıklamalar:

* SQLALCHEMY_DATABASE_URL: Veritabanı bağlantı dizesi. postgresql://kullanici:parola@host:port/veritabani_adi formatındadır. Güvenlik nedeniyle parolanızı doğrudan koda yazmak yerine ortam değişkenlerinden almanızı öneririz.
* create_engine: SQLAlchemy’nin veritabanına bağlanmak için kullandığı motoru oluşturur.
* sessionmaker: Her istek için bir veritabanı oturumu (session) oluşturmak için kullanılır. autocommit=False ve autoflush=False ayarları, işlemleri manuel olarak yönetmemizi sağlar.
* declarative_base(): SQLAlchemy ORM modellerimizin miras alacağı temel sınıfı oluşturur.
* get_db(): FastAPI’nin bağımlılık enjeksiyonu sistemiyle uyumlu, bir veritabanı oturumu sağlayan bir jeneratör fonksiyonudur. Her istek başladığında bir oturum açar ve istek tamamlandığında oturumu kapatır.

Veritabanı Modelleri (models.py)

Bu dosya, veritabanı tablolarımızı temsil eden SQLAlchemy ORM modellerini içerir.

# fastapidb_app/models.py

from sqlalchemy import Boolean, Column, Integer, String
from sqlalchemy.orm import relationship

from .database import Base

class User(Base):
    __tablename__ = "users" # Veritabanındaki tablo adı

    id = Column(Integer, primary_key=True, index=True) # Birincil anahtar, otomatik artan
    email = Column(String, unique=True, index=True) # E-posta, benzersiz ve indeksli
    hashed_password = Column(String) # Şifrenin hash'lenmiş hali
    is_active = Column(Boolean, default=True) # Kullanıcının aktif olup olmadığını belirtir

    # İlişkili modeller buraya eklenebilir (örneğin, bir kullanıcının birden fazla öğesi olabilir)
    # items = relationship("Item", back_populates="owner")

Örnek olarak bir Item modeli de ekleyebiliriz (isteğe bağlı)

class Item(Base):

__tablename__ = "items"

# id = Column(Integer, primary_key=True, index=True)

title = Column(String, index=True)

description = Column(String, index=True)

owner_id = Column(Integer, ForeignKey("users.id"))

# owner = relationship("User", back_populates="items")

Açıklamalar:

* Base: database.py dosyasından içe aktardığımız temel sınıftır. Tüm ORM modellerimiz bu sınıftan miras almalıdır.
* __tablename__: Bu sınıfın veritabanında hangi tabloyu temsil ettiğini belirtir.
* Column: Tablo sütunlarını tanımlamak için kullanılır.
* Integer, String, Boolean: SQLAlchemy’nin veri tipleri.
* primary_key=True: Bu sütunun birincil anahtar olduğunu belirtir.
* index=True: Bu sütun üzerinde bir veritabanı indeksi oluşturur, bu da sorgu performansını artırabilir.
* unique=True: Bu sütundaki değerlerin benzersiz olması gerektiğini belirtir.
* relationship: İlişkili modeller arasında bağlantı kurmak için kullanılır (örneğin, bir kullanıcının birçok öğesi olabilir).

Pydantic ile Veri Şemaları

Pydantic, Python’da veri doğrulama ve ayarlar yönetimi için kullanılan bir kütüphanedir. FastAPI, Pydantic’i API isteklerinin gövdelerini doğrulamak, yanıtları serileştirmek ve otomatik OpenAPI dokümantasyonu oluşturmak için yoğun bir şekilde kullanır.

Giriş ve Çıkış Veri Modelleri (schemas.py)

API’miz için Pydantic modellerini tanımlayacağız. Genellikle, kullanıcıdan alınan veriler (giriş şemaları) ve kullanıcıya geri gönderilen veriler (çıkış şemaları) için farklı modeller tanımlamak iyi bir pratiktir.

# fastapidb_app/schemas.py

from pydantic import BaseModel, EmailStr
from typing import List, Optional

Temel kullanıcı şeması - e-posta ve aktiflik durumu

class UserBase(BaseModel): email: EmailStr # E-posta formatında olmalı is_active: Optional[bool] = True # İsteğe bağlı, varsayılan True

Kullanıcı oluşturma şeması - UserBase'e ek olarak parola içerir

class UserCreate(UserBase): password: str

Kullanıcı güncelleme şeması (isteğe bağlı alanlar)

class UserUpdate(UserBase): password: Optional[str] = None

API yanıtı için kullanıcı şeması - hassas bilgileri (parola) içermez

class User(UserBase): id: int # Veritabanından gelen id # items: List[Item] = [] # İlişkili öğeler varsa eklenebilir class Config: orm_mode = True # SQLAlchemy ORM modelleriyle uyumlu çalışmasını sağlar (eski adıyla orm_mode = True) # FastAPI 0.100.0 ve sonrası için from_attributes = True kullanılması önerilir. # Eğer FastAPI sürümünüz yeniyse, aşağıdaki gibi değiştirin: # from_attributes = True

Örnek olarak Item şemaları (isteğe bağlı)

class ItemBase(BaseModel):

title: str

description: Optional[str] = None

# class ItemCreate(ItemBase):

pass

# class Item(ItemBase):

id: int

owner_id: int

# class Config:

orm_mode = True

# from_attributes = True

Açıklamalar:

* BaseModel: Tüm Pydantic modellerinin miras alacağı temel sınıftır.
* EmailStr: Pydantic’in e-posta formatını doğrulayan özel bir tipi.
* Optional: Bir alanın isteğe bağlı olduğunu belirtir.
* UserCreate: Kullanıcı oluştururken password alanının da zorunlu olmasını sağlar.
* User: API’den yanıt olarak dönecek kullanıcı verisinin yapısını tanımlar. hashed_password gibi hassas alanları içermez.
* Config.orm_mode = True (veya from_attributes = True): Bu ayar, Pydantic modelinin SQLAlchemy ORM modelinden doğrudan veri okuyabilmesini sağlar. Yani, bir User ORM nesnesini doğrudan bir User Pydantic modeline dönüştürebiliriz.

CRUD İşlemleri

CRUD (Create, Read, Update, Delete) işlemleri, bir veritabanıyla yapılan temel etkileşimlerdir. Bu işlemleri ayrı bir modülde tanımlamak, kodunuzu daha düzenli ve test edilebilir hale getirir.

Veritabanı Etkileşim Fonksiyonları (crud.py)

Bu dosya, veritabanı oturumunu kullanarak kullanıcıları oluşturma, okuma, güncelleme ve silme gibi işlevleri sağlar.

# fastapidb_app/crud.py

from sqlalchemy.orm import Session
from sqlalchemy import func # func'ı import etmeyi unutmayın

from . import models, schemas
from passlib.context import CryptContext # Şifre hash'leme için

Şifre hash'leme bağlamını oluştur

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

Şifreyi hash'leyen yardımcı fonksiyon

def get_password_hash(password: str): return pwd_context.hash(password)

Şifreyi doğrulayan yardımcı fonksiyon

def verify_password(plain_password: str, hashed_password: str): return pwd_context.verify(plain_password, hashed_password)

Kullanıcıyı ID'ye göre getir

def get_user(db: Session, user_id: int): return db.query(models.User).filter(models.User.id == user_id).first()

Kullanıcıyı e-postaya göre getir

def get_user_by_email(db: Session, email: str): return db.query(models.User).filter(models.User.email == email).first()

Tüm kullanıcıları getir (belirli bir atlama ve limit ile sayfalama için)

def get_users(db: Session, skip: int = 0, limit: int = 100): return db.query(models.User).offset(skip).limit(limit).all()

Yeni bir kullanıcı oluştur

def create_user(db: Session, user: schemas.UserCreate): hashed_password = get_password_hash(user.password) db_user = models.User(email=user.email, hashed_password=hashed_password, is_active=user.is_active) db.add(db_user) db.commit() # Değişiklikleri veritabanına kaydet db.refresh(db_user) # Veritabanından güncel verileri (örn. id) al return db_user

Kullanıcıyı güncelle

def update_user(db: Session, user_id: int, user_update: schemas.UserUpdate): db_user = db.query(models.User).filter(models.User.id == user_id).first() if db_user: # Pydantic modelinden gelen alanları SQLAlchemy modeline uygula update_data = user_update.dict(exclude_unset=True) # Sadece ayarlanmış alanları al if "password" in update_data and update_data["password"]: db_user.hashed_password = get_password_hash(update_data["password"]) del update_data["password"] # Parola zaten işlendi, diğer güncellemelere dahil etme for key, value in update_data.items(): setattr(db_user, key, value) db.add(db_user) db.commit() db.refresh(db_user) return db_user

Kullanıcıyı sil

def delete_user(db: Session, user_id: int): db_user = db.query(models.User).filter(models.User.id == user_id).first() if db_user: db.delete(db_user) db.commit() return True return False

Toplam kullanıcı sayısını döndür

def get_users_count(db: Session): return db.query(func.count(models.User.id)).scalar()

Açıklamalar:

* Session: database.py dosyasından gelen veritabanı oturumu tipidir. FastAPI bağımlılık enjeksiyonu ile sağlanacaktır.
* pwd_context: passlib kütüphanesinden şifre hash’leme ve doğrulama için kullanılır. Şifreleri doğrudan veritabanında saklamak yerine hash’leyerek saklamak zorunludur.
* db.query(models.User): User modeline karşılık gelen tablo üzerinde bir sorgu başlatır.
* filter(), first(), all(): Sorgu sonuçlarını filtrelemek ve almak için kullanılır.
* db.add(), db.commit(), db.refresh(): Veritabanına yeni bir nesne eklemek, değişiklikleri kaydetmek ve eklenen nesnenin veritabanı tarafından oluşturulan id gibi alanlarını güncellemek için kullanılır.
* db.delete(): Bir nesneyi veritabanından siler.
* update_user fonksiyonunda user_update.dict(exclude_unset=True) kullanarak sadece Pydantic modelinde belirtilen ve değeri değiştirilen alanları güncelleriz.

FastAPI Yönlendiricileri ve Bağımlılık Enjeksiyonu

FastAPI, API uç noktalarını (rotaları) tanımlamak için dekoratörler kullanır ve bağımlılık enjeksiyonu (Dependency Injection) ile veritabanı oturumları gibi kaynakları kolayca yönetmenizi sağlar.

API Uç Noktaları (main.py)

Bu dosya, FastAPI uygulamanızın ana giriş noktasıdır ve API rotalarını tanımlar.

# fastapidb_app/main.py

from typing import List
from fastapi import FastAPI, Depends, HTTPException, status
from sqlalchemy.orm import Session

from . import crud, models, schemas
from .database import SessionLocal, engine, get_db

Veritabanı tablolarını oluştur (Alembic kullanıyorsak bu satıra gerek kalmaz)

models.Base.metadata.create_all(bind=engine)

app = FastAPI( title="FastAPI Kullanıcı Yönetimi", description="SQLAlchemy ve PostgreSQL ile temel kullanıcı CRUD işlemleri.", version="1.0.0", )

Root endpoint

@app.get("/", summary="Uygulamanın çalışıp çalışmadığını kontrol et") async def root(): return {"message": "FastAPI uygulaması çalışıyor!"}

Kullanıcı oluşturma endpoint'i

@app.post("/users/", response_model=schemas.User, status_code=status.HTTP_201_CREATED, summary="Yeni kullanıcı oluştur") def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)): db_user = crud.get_user_by_email(db, email=user.email) if db_user: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="E-posta zaten kayıtlı") return crud.create_user(db=db, user=user)

Tüm kullanıcıları listeleme endpoint'i (sayfalama ile)

@app.get("/users/", response_model=List[schemas.User], summary="Tüm kullanıcıları listele") def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): users = crud.get_users(db, skip=skip, limit=limit) return users

Belirli bir kullanıcıyı ID'ye göre getirme endpoint'i

@app.get("/users/{user_id}", response_model=schemas.User, summary="ID'ye göre kullanıcı getir") def read_user(user_id: int, db: Session = Depends(get_db)): db_user = crud.get_user(db, user_id=user_id) if db_user is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Kullanıcı bulunamadı") return db_user

Kullanıcı güncelleme endpoint'i

@app.put("/users/{user_id}", response_model=schemas.User, summary="Kullanıcı bilgilerini güncelle") def update_user(user_id: int, user_update: schemas.UserUpdate, db: Session = Depends(get_db)): db_user = crud.get_user(db, user_id=user_id) if db_user is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Kullanıcı bulunamadı") # E-posta güncelleniyorsa ve zaten kullanılıyorsa kontrol et if user_update.email and user_update.email != db_user.email: existing_user = crud.get_user_by_email(db, email=user_update.email) if existing_user: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Bu e-posta zaten başka bir kullanıcı tarafından kullanılıyor") updated_user = crud.update_user(db=db, user_id=user_id, user_update=user_update) return updated_user

Kullanıcı silme endpoint'i

@app.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT, summary="Kullanıcıyı sil") def delete_user(user_id: int, db: Session = Depends(get_db)): if not crud.delete_user(db, user_id=user_id): raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Kullanıcı bulunamadı") return {"message": "Kullanıcı başarıyla silindi"}

Toplam kullanıcı sayısını getiren endpoint

@app.get("/users/count/", summary="Toplam kullanıcı sayısını getir") def get_total_users_count(db: Session = Depends(get_db)): count = crud.get_users_count(db) return {"total_users": count}

Açıklamalar:

* FastAPI(): FastAPI uygulamasının bir örneğini oluşturur. title, description, version gibi parametreler OpenAPI dokümantasyonunda görünür.
* models.Base.metadata.create_all(bind=engine): Bu satır, models.py dosyasında tanımlanan tüm tabloları veritabanında oluşturur. Ancak, Alembic gibi bir migrasyon aracı kullanıyorsanız, bu satırı yorum satırı yapmalı veya kaldırmalısınız. Aksi takdirde, Alembic’in sorumluluğundaki veritabanı şema yönetimini atlamış olursunuz.
* @app.post, @app.get, @app.put, @app.delete: FastAPI’nin HTTP metotlarına karşılık gelen dekoratörleridir. API uç noktalarını tanımlar.
* response_model=schemas.User: FastAPI’ye bu uç noktanın yanıtının schemas.User Pydantic modeline uygun olacağını bildirir. Bu, otomatik dokümantasyon ve yanıt serileştirmesi için önemlidir.
* status_code=...: Yanıtın HTTP durum kodunu belirtir.
* db: Session = Depends(get_db): FastAPI’nin bağımlılık enjeksiyon sistemidir. Her istekte get_db fonksiyonunu çağırarak bir veritabanı oturumu (Session) sağlar ve istek tamamlandığında oturumu kapatır.
* HTTPException: Bir hata durumu oluştuğunda belirli bir HTTP durum kodu ve detay mesajı ile yanıt dönmek için kullanılır.

Uygulamayı Çalıştırma

FastAPI uygulamanızı Uvicorn ASGI sunucusu ile çalıştırabilirsiniz.

uvicorn main:app --reload

* main: main.py dosyasının adıdır.
* app: main.py dosyasındaki FastAPI() örneğinin adıdır.
* --reload: Kodunuzda yaptığınız değişiklikleri otomatik olarak algılar ve sunucuyu yeniden başlatır, bu da geliştirme sürecinde çok kullanışlıdır.

Uygulama çalışmaya başladığında, terminalde şöyle bir çıktı görmelisiniz:

INFO:     Will watch for changes in these directories: ['/home/youruser/fastapidb_app']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [xxxxx] using statreload
INFO:     Started server process [xxxxx]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Şimdi bir web tarayıcısı açın ve aşağıdaki adreslere gidin:

* API Dokümantasyonu (Swagger UI): http://127.0.0.1:8000/docs
* Alternatif Dokümantasyon (ReDoc): http://127.0.0.1:8000/redoc

Bu arayüzler sayesinde, oluşturduğunuz API uç noktalarını görsel olarak inceleyebilir, istekler gönderebilir ve yanıtları görebilirsiniz.

Veritabanı Migrasyonları (Alembic ile)

Uygulama geliştirme sürecinde veritabanı şemanızın zamanla değişmesi kaçınılmazdır (yeni tablolar ekleme, mevcut tabloları değiştirme, sütun ekleme/çıkarma vb.). Veritabanı migrasyonları, bu şema değişikliklerini sürüm kontrolü altında yönetmenizi sağlar. Alembic, SQLAlchemy ile entegre çalışan popüler bir migrasyon aracıdır.

Neden Migrasyonlar?

* Sürüm Kontrolü: Veritabanı şema değişiklikleri kodunuz gibi sürüm kontrolü altında tutulur.
* Geliştirici İşbirliği: Birden fazla geliştiricinin aynı veritabanı şeması üzerinde çalışmasını kolaylaştırır.
* Otomasyon: Şema değişikliklerini test ve üretim ortamlarına otomatik olarak uygulamayı sağlar.
* Geri Alma Yeteneği: Yanlış bir migrasyonu geri alma veya belirli bir şema sürümüne dönme yeteneği sunar.

Alembic Kurulumu

Daha önce pip install alembic komutuyla Alembic’i kurmuştuk.

Alembic Projesini Başlatma

Proje dizininizin kökünde (yani fastapidb_app içinde), Alembic projesini başlatın:

alembic init alembic

Bu komut, alembic adında bir dizin ve alembic.ini adında bir yapılandırma dosyası oluşturacaktır.

* alembic.ini: Alembic’in genel yapılandırma ayarlarını içerir.
* alembic/versions/: Migrasyon dosyalarının depolandığı yer.
* alembic/env.py: Alembic’in veritabanıyla nasıl etkileşim kuracağını tanımlayan Python betiği.

alembic.ini Yapılandırması

alembic.ini dosyasını açın ve sqlalchemy.url satırını veritabanı bağlantı dizinizle güncelleyin:

# alembic.ini

... diğer ayarlar ...

sqlalchemy.url = postgresql://fastapiuser:your_strong_password@localhost/fastapidb

... diğer ayarlar ...

Ayrıca, Alembic’in SQLAlchemy ORM modellerinizi (models.py dosyasındaki Base) tanıması için alembic/env.py dosyasını düzenlemeniz gerekir. env.py dosyasında target_metadata = None satırını bulun ve aşağıdaki gibi değiştirin:

# alembic/env.py

... diğer içe aktarmalar ...

from fastapidb_app.database import Base from fastapidb_app import models # models.py dosyasını da import ettiğinizden emin olun

... diğer ayarlar ...

target_metadata, SQLAlchemy Base nesnesidir, Alembic'in şema değişikliklerini algılaması için gereklidir.

target_metadata = Base.metadata

... diğer ayarlar ...

Bu değişiklik, Alembic’in Base.metadata içindeki tüm tanımlı modelleri görmesini ve veritabanı şemasını bu modellere göre karşılaştırmasını sağlar.

Migrasyon Oluşturma ve Uygulama

Şimdi ilk migrasyonumuzu oluşturalım. Bu migrasyon, models.py dosyasında tanımladığımız User tablosunu veritabanında oluşturacaktır.

alembic revision --autogenerate -m "Create User table"

* revision: Yeni bir migrasyon dosyası oluşturur.
* --autogenerate: Alembic’in mevcut veritabanı şeması ile models.py dosyasındaki tanımlar arasındaki farkları otomatik olarak algılamasını ve migrasyon betiğini oluşturmasını sağlar.
* -m "Create User table": Migrasyona açıklayıcı bir mesaj ekler.

Bu komut, alembic/versions/ dizininde zaman damgası içeren bir Python dosyası oluşturacaktır. Bu dosyayı açıp otomatik olarak oluşturulan upgrade() ve downgrade() fonksiyonlarını inceleyebilirsiniz.

Migrasyon dosyasını oluşturduktan sonra, bu migrasyonu veritabanına uygulamak için:

alembic upgrade head

* upgrade: Migrasyonları uygular.
* head: En son migrasyonu uygula anlamına gelir.

Artık veritabanınızda users tablosu oluşturulmuş olmalıdır. Bu adımdan sonra main.py dosyasındaki models.Base.metadata.create_all(bind=engine) satırını kesinlikle yorum satırı yapın veya silin. Aksi takdirde, Alembic’in yönetimini atlamış olursunuz.

Daha sonra models.py dosyanızda bir değişiklik yaptığınızda (örneğin, User modeline yeni bir sütun eklediğinizde), sadece alembic revision --autogenerate -m "Add new column to User" komutunu çalıştırın ve ardından alembic upgrade head ile uygulayın.

Güvenlik ve Performans İpuçları

FastAPI ve ilişkisel veritabanı kullanan bir uygulamayı geliştirirken güvenlik ve performans her zaman ön planda olmalıdır.

Güvenlik

* Parola Hash’leme: Asla düz metin parolaları veritabanında saklamayın. passlib gibi kütüphaneler kullanarak parolaları güvenli bir şekilde hash’leyin (bcrypt önerilir).
* Kimlik Doğrulama ve Yetkilendirme: Kullanıcıları doğrulamak ve yetkilendirmek için JWT (JSON Web Tokens), OAuth2 veya API Anahtarları gibi standart mekanizmaları kullanın. FastAPI, OAuth2 ile entegrasyon için yerleşik araçlara sahiptir.
* Ortam Değişkenleri: Hassas bilgileri (veritabanı kimlik bilgileri, API anahtarları vb.) doğrudan koda yazmak yerine ortam değişkenleri (.env dosyası ve python-dotenv kütüphanesi ile) kullanarak yönetin.
* Giriş Doğrulaması: Pydantic kullanarak API giriş verilerini titizlikle doğrulayın. Bu, SQL enjeksiyonu ve XSS gibi yaygın güvenlik açıklarını önlemeye yardımcı olur.
* HTTPS Kullanımı: Üretim ortamında her zaman HTTPS kullanın.
* CORS (Cross-Origin Resource Sharing): API’nize erişebilecek alan adlarını dikkatlice yapılandırın.

Performans

* Asenkron Veritabanı Sürücüleri: psycopg2-binary gibi senkron sürücüler yerine asyncpg (PostgreSQL için) veya asyncmy (MySQL için) gibi asenkron veritabanı sürücüleri kullanmayı düşünün. Bu, veritabanı I/O işlemlerini beklerken FastAPI’nin diğer görevleri işlemesine olanak tanır.
* pip install asyncpg sqlalchemy[asyncio] (PostgreSQL için)
* create_engine yerine create_async_engine kullanın ve SessionLocal yerine async_sessionmaker kullanın.
* get_db fonksiyonunuzu da asenkron yapmanız gerekir (async def get_db(): async with SessionLocal() as session: yield session).
* Veritabanı Bağlantı Havuzları: SQLAlchemy’nin varsayılan olarak bir bağlantı havuzu vardır, ancak performans ihtiyaçlarınıza göre boyutunu ve davranışını ayarlayabilirsiniz.
* Sorgu Optimizasyonu: N+1 sorgu sorunlarından kaçının. relationship yüklemesini selectinload veya joinedload ile optimize edin.
* İndeksleme: Veritabanı tablolarınızda sıkça sorgulanan sütunlar üzerinde uygun indeksler oluşturun.
* Önbellekleme: Sık erişilen ancak nadiren değişen veriler için Redis veya Memcached gibi bir önbellekleme katmanı kullanın.
* Sayfalama: Büyük veri kümelerini döndürürken API’lerde sayfalama (skip ve limit parametreleri gibi) uygulayın.
* Gunicorn ile Çalıştırma: Üretim ortamında Uvicorn’u doğrudan çalıştırmak yerine, Gunicorn gibi bir WSGI/ASGI sunucusu arkasında birden fazla worker ile çalıştırmak daha iyi performans ve kararlılık sağlar.
* pip install gunicorn
* gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app (4 worker ile çalıştırma örneği)

Sonuç

Bu kapsamlı makalede, Ubuntu üzerinde FastAPI’yi bir ilişkisel veritabanı olan PostgreSQL ile nasıl entegre edeceğimizi adım adım inceledik. Python sanal ortamı kurulumundan başlayarak, PostgreSQL veritabanı ve kullanıcısı oluşturmaya, FastAPI, SQLAlchemy ve Pydantic kütüphanelerini kullanarak bir API oluşturmaya kadar birçok konuyu ele aldık. Ayrıca, veritabanı şema değişikliklerini yönetmek için Alembic migrasyon aracının önemini ve kullanımını da öğrendik.

FastAPI’nin modern, asenkron yapısı ve Pydantic’in güçlü veri doğrulama yetenekleri, SQLAlchemy’nin esnek ORM’i ile birleştiğinde, hızlı, güvenilir ve bakımı kolay web API’ları geliştirmeniz için sağlam bir temel sunar. İlişkisel veritabanlarının yapısal bütünlüğü ve sorgu yetenekleri, bu kombinasyonu birçok karmaşık iş uygulaması için ideal hale getirir.

Bu rehber, temel bir kullanıcı yönetimi API’si örneği üzerinden ilerlemiş olsa da, burada öğrenilen prensipler ve teknikler, daha karmaşık ve büyük ölçekli uygulamalar için de geçerlidir. Bir sonraki adım olarak, uygulamanıza kimlik doğrulama (JWT veya OAuth2), daha gelişmiş hata yönetimi, test yazımı ve üretim ortamına dağıtım gibi özellikleri eklemeyi düşünebilirsiniz. Unutmayın, iyi bir yazılım geliştirme pratiği, sürekli öğrenmeyi ve güvenlik ile performans optimizasyonlarına dikkat etmeyi gerektirir.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

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

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Exit mobile version