İçeriğe geç
Educora
İleri20 dk27 / 42

FastAPI ile web servisi

FastAPI ile küçük bir REST API oluştur: yol ve sorgu parametreleri, Pydantic modelleriyle doğrulama, 201 ve 404 yanıtları, otomatik belgeler (`/docs`), sunucuyu kendi bilgisayarında çalıştırmak ve `TestClient` ile test etmek.

Kendini test et
Bu derste öğreneceklerin
  • Bir FastAPI uygulaması oluşturmak ve fastapi dev ya da uvicorn ile yerelde çalıştırmak
  • Yol ve sorgu parametrelerini türlerle tanımlamak, JSON gövdesini bir Pydantic modeliyle doğrulamak
  • Doğru durum kodlarını döndürmek ve API'yi /docs ve TestClient ile kontrol etmek

Önceki derste istemciydik ve başkasının API'sine istek gönderiyorduk. Şimdi rolleri değiştirip kendi sunucumuzu yazacağız. FastAPI modern bir Python çatısıdır: fonksiyon parametrelerindeki tür ipuçlarını (type hints) kullanarak gelen veriyi kendisi doğrular, JSON'a çevirir ve etkileşimli belgeler oluşturur. Bir mobil uygulama için arka uç, küçük bir mikroservis ya da API olarak sunulan bir makine öğrenmesi modeli: FastAPI bunların hepsi için popüler bir seçimdir.

İlk uygulama ve yerelde çalıştırma

Bir sunucu tarayıcıda çalışamaz; bu yüzden bu dersin kodu burada çalıştırılmaz, onu kendi bilgisayarında (Python 3.10 ya da daha yeni) dene. @app.get('/yol') dekoratörü bir fonksiyonu o adrese gelen GET isteklerine bağlar; fonksiyonun döndürdüğü sözlük otomatik olarak bir JSON yanıtına dönüşür.

Python
from fastapi import FastAPI

app = FastAPI(title='Educora Demo API')


@app.get('/')
def root():
    return {'message': 'Hello from FastAPI'}


@app.get('/square/{number}')
def square(number: int):
    return {'number': number, 'square': number ** 2}


@app.get('/greet')
def greet(name: str, lang: str = 'en'):
    greetings = {'en': 'Hello', 'az': 'Salam', 'ru': 'Привет', 'tr': 'Merhaba'}
    word = greetings.get(lang, 'Hello')
    return {'text': f'{word}, {name}!'}
main.py dosyası. {number} bir yol parametresidir; name ve lang yolda olmadığı için sorgu parametreleridir; lang'ın varsayılan değeri olduğu için isteğe bağlıdır.
  1. 1
    Sanal ortam oluştur

    Proje klasöründe python -m venv .venv çalıştır ve ortamı etkinleştir: Windows'ta .venv\Scripts\activate, Linux ve macOS'ta source .venv/bin/activate.

  2. 2
    FastAPI'yi kur

    pip install "fastapi[standard]" — FastAPI ile birlikte uvicorn sunucusu ve fastapi komutu da kurulur.

  3. 3
    Sunucuyu başlat

    fastapi dev main.py (ya da uvicorn main:app --reload). Sunucu http://127.0.0.1:8000 adresinde çalışır ve dosya değiştiğinde kendini yeniden başlatır.

  4. 4
    Belgeleri aç

    Tarayıcıda http://127.0.0.1:8000/docs sayfasını aç; tüm uç noktalar orada listelenir ve “Try it out” düğmesiyle doğrudan denenebilir.

Terminal
curl http://127.0.0.1:8000/square/12
curl "http://127.0.0.1:8000/greet?name=Aysel&lang=az"
curl http://127.0.0.1:8000/square/abc
Beklenen çıktı
{"number":12,"square":144}
{"text":"Salam, Aysel!"}
{"detail":[{"type":"int_parsing","loc":["path","number"],"msg":"Input should be a valid integer, unable to parse string as an integer","input":"abc"}]}
abc bir tam sayı olmadığı için FastAPI fonksiyonu hiç çağırmaz ve hatanın nerede olduğunu açıklayan bir yanıtla 422 kodunu döndürür. Windows PowerShell'de curl yerine curl.exe yaz.

Pydantic modelleriyle REST API

Bir POST isteğinin JSON gövdesini bir Pydantic modeli tanımlar: BaseModel'den türeyen bir sınıf alanları ve türlerini listeler, Field ise ek koşullar koyar (örneğin 1–100 karakterlik bir başlık). Fonksiyonun dönüş türü (-> Task) yanıtı da doğrular ve fazla alanları ayıklar. Görevler için küçük bir API kuralım; kolaylık olsun diye veriler bellekteki bir sözlükte tutuluyor.

Python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field

app = FastAPI(title='Educora Tasks API')


class TaskIn(BaseModel):
    title: str = Field(min_length=1, max_length=100)
    subject: str = 'python'
    done: bool = False


class Task(TaskIn):
    id: int


tasks: dict[int, Task] = {}


@app.post('/tasks', status_code=201)
def create_task(task: TaskIn) -> Task:
    new = Task(id=len(tasks) + 1, **task.model_dump())
    tasks[new.id] = new
    return new
tasks.py, 1. bölüm: modeller ve oluşturma. İstemci id göndermez, onu sunucu atar; bu yüzden giriş (TaskIn) ve çıkış (Task) modelleri ayrıdır.
Python
@app.get('/tasks')
def list_tasks(subject: str | None = None, limit: int = 10) -> list[Task]:
    found = [t for t in tasks.values() if subject is None or t.subject == subject]
    return found[:limit]


@app.get('/tasks/{task_id}')
def get_task(task_id: int) -> Task:
    if task_id not in tasks:
        raise HTTPException(status_code=404, detail='Task not found')
    return tasks[task_id]
tasks.py, 2. bölüm: okuma. HTTPException fonksiyonu durdurur ve istemciye 404 koduyla {"detail": "Task not found"} gönderir. Sunucuyu fastapi dev tasks.py ile başlat.
İstekNe yaparYanıt
POST /tasksyeni bir görev oluşturur201 ya da 422 (geçersiz gövde)
GET /tasks?subject=python&limit=5filtrelenmiş bir liste döndürür200
GET /tasks/{task_id}tek bir görevi döndürür200 ya da 404

API'yi test etmek

TestClient, gerçek bir sunucu başlatmadan uygulamayı doğrudan çağırır; istekler ve yanıtlar tamamen gerçektir. Bu, pytest testleri için idealdir: kodu her değiştirdiğinde tüm uç noktaları saniyeler içinde kontrol edebilirsin.

Python
from fastapi.testclient import TestClient
from tasks import app

client = TestClient(app)
r = client.post('/tasks', json={'title': 'Learn FastAPI'})
print(r.status_code, r.json())
client.post('/tasks', json={'title': 'Revise SQL', 'subject': 'sql'})
print(client.get('/tasks', params={'subject': 'python'}).json())
r = client.get('/tasks/99')
print(r.status_code, r.json())
r = client.post('/tasks', json={'title': ''})
print(r.status_code, r.json()['detail'][0]['msg'])
Beklenen çıktı
201 {'title': 'Learn FastAPI', 'subject': 'python', 'done': False, 'id': 1}
[{'title': 'Learn FastAPI', 'subject': 'python', 'done': False, 'id': 1}]
404 {'detail': 'Task not found'}
422 String should have at least 1 character
Boş bir başlık Field(min_length=1) kuralını bozar; Pydantic isteği fonksiyona ulaşmadan reddeder. subject gönderilmediğinde varsayılan 'python' değeri kullanılır.

Önemli noktalar

  • app = FastAPI() ile @app.get(...) ve @app.post(...) dekoratörleri fonksiyonları adreslere bağlar; döndürülen sözlük JSON olur.
  • Yoldaki {ad} bir yol parametresidir, diğer argümanlar sorgu parametreleridir; türler otomatik olarak doğrulanır (hatada 422).
  • Pydantic'in BaseModel ve Field yapıları JSON gövdesini tanımlar ve doğrular; status_code=201 ve HTTPException(404) doğru yanıtlar verir.
  • Yerelde çalıştırma: pip install "fastapi[standard]", ardından fastapi dev main.py; belgeler /docs ve /redoc adreslerindedir.
  • TestClient API'yi sunucu olmadan test eder; gerçek verileri bellekte değil, bir veritabanında sakla.

Kendini test et

10 soru. Her doğru cevap XP kazandırır.

1 / 10
@app.get('/users/{user_id}') ile def get_user(user_id: int, full: bool = False) fonksiyonunda full nedir?