Ana içeriğe geç

Yol Parametreleri

Yol "parametrelerini" veya "değişkenlerini" Python string biçimlemede kullanılan sözdizimi ile tanımlayabilirsiniz.

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id):
    return {"item_id": item_id}

Yol parametresi olan item_id'nin değeri, fonksiyonunuza item_id argümanı olarak aktarılacaktır.

Eğer bu örneği çalıştırıp http://127.0.0.1:8000/items/foo sayfasına giderseniz, şöyle bir çıktı ile karşılaşırsınız:

{"item_id":"foo"}

Tip İçeren Yol Parametreleri

Standart Python tip belirteçlerini kullanarak yol parametresinin tipini fonksiyonun içerisinde tanımlayabilirsiniz.

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}

Bu durumda, item_id bir int olarak tanımlanacaktır.

Ek bilgi

Bu sayede, fonksiyon içerisinde hata denetimi, kod tamamlama gibi konularda editör desteğine kavuşacaksınız.

Veri Dönüşümü

Eğer bu örneği çalıştırıp tarayıcınızda http://127.0.0.1:8000/items/3 sayfasını açarsanız, şöyle bir yanıt ile karşılaşırsınız:

{"item_id":3}

Ek bilgi

Dikkatinizi çekerim ki, fonksiyonunuzun aldığı (ve döndürdüğü) değer olan 3 bir string "3" değil aksine bir Python int'idir.

Bu tanımlamayla birlikte, FastAPI size otomatik istek "ayrıştırma" özelliği sağlar.

Veri Doğrulama

Eğer tarayıcınızda http://127.0.0.1:8000/items/foo sayfasını açarsanız, şuna benzer güzel bir HTTP hatası ile karşılaşırsınız:

{
  "detail": [
    {
      "type": "int_parsing",
      "loc": [
        "path",
        "item_id"
      ],
      "msg": "Input should be a valid integer, unable to parse string as an integer",
      "input": "foo",
      "url": "https://errors.pydantic.dev/2.1/v/int_parsing"
    }
  ]
}

Çünkü burada item_id yol parametresi int tipinde bir değer beklerken "foo" yani string tipinde bir değer almıştı.

Aynı hata http://127.0.0.1:8000/items/4.2 sayfasında olduğu gibi int yerine float bir değer verseydik de ortaya çıkardı.

Ek bilgi

Böylece, aynı Python tip tanımlaması ile birlikte, FastAPI veri doğrulama özelliği sağlar.

Dikkatinizi çekerim ki, karşılaştığınız hata, doğrulamanın geçersiz olduğu mutlak noktayı da açık bir şekilde belirtiyor.

Bu özellik, API'ınızla iletişime geçen kodu geliştirirken ve ayıklarken inanılmaz derecede yararlı olacaktır.

Dokümantasyon

Ayrıca, tarayıcınızı http://127.0.0.1:8000/docs adresinde açarsanız, aşağıdaki gibi otomatik ve interaktif bir API dökümantasyonu ile karşılaşırsınız:

Ek bilgi

Üstelik, sadece aynı Python tip tanımlaması ile, FastAPI size otomatik ve interaktif (Swagger UI ile entegre) bir dokümantasyon sağlar.

Dikkatinizi çekerim ki, yol parametresi integer olarak tanımlanmıştır.

Standartlara Dayalı Avantajlar, Alternatif Dokümantasyon

Oluşturulan şema OpenAPI standardına uygun olduğu için birçok uyumlu araç mevcuttur.

Bu sayede, FastAPI'ın bizzat kendisi http://127.0.0.1:8000/redoc sayfasından erişebileceğiniz alternatif (ReDoc kullanan) bir API dokümantasyonu sağlar:

Aynı şekilde, farklı diller için kod türetme araçları da dahil olmak üzere çok sayıda uyumlu araç bulunur.

Pydantic

Tüm veri doğrulamaları Pydantic tarafından arka planda gerçekleştirilir, bu sayede tüm avantajlardan faydalanabilirsiniz. Böylece, emin ellerde olduğunuzu hissedebilirsiniz.

Aynı tip tanımlamalarını str, float, bool ve diğer karmaşık veri tipleri ile kullanma imkanınız vardır.

Bunlardan birkaçı, bu eğitimin ileriki bölümlerinde irdelenmiştir.

Sıralama Önem Arz Eder

Yol operasyonları tasarlarken sabit yol barındıran durumlar ile karşılaşabilirsiniz.

Farz edelim ki /users/me yolu geçerli kullanıcı hakkında bilgi almak için kullanılıyor olsun.

Benzer şekilde /users/{user_id} gibi tanımlanmış ve belirli bir kullanıcı hakkında veri almak için kullanıcının ID bilgisini kullanan bir yolunuz da mevcut olabilir.

Yol operasyonları sıralı bir şekilde gözden geçirildiğinden dolayı /users/me yolunun /users/{user_id} yolundan önce tanımlanmış olmasından emin olmanız gerekmektedir:

from fastapi import FastAPI

app = FastAPI()


@app.get("/users/me")
async def read_user_me():
    return {"user_id": "the current user"}


@app.get("/users/{user_id}")
async def read_user(user_id: str):
    return {"user_id": user_id}

Aksi halde, /users/{user_id} yolu "me" değerinin user_id parametresi için gönderildiğini "düşünerek" /users/me ile de eşleşir.

Benzer şekilde, bir yol operasyonunu yeniden tanımlamanız mümkün değildir:

from fastapi import FastAPI

app = FastAPI()


@app.get("/users")
async def read_users():
    return ["Rick", "Morty"]


@app.get("/users")
async def read_users2():
    return ["Bean", "Elfo"]

Yol, ilk kısım ile eşleştiğinden dolayı her koşulda ilk yol operasyonu kullanılacaktır.

Ön Tanımlı Değerler

Eğer yol parametresi alan bir yol operasyonunuz varsa ve alabileceği yol parametresi değerlerinin ön tanımlı olmasını istiyorsanız, standart Python Enum tipini kullanabilirsiniz.

Bir Enum Sınıfı Oluşturalım

Enum sınıfını projemize dahil edip str ile Enum sınıflarını miras alan bir alt sınıf yaratalım.

str sınıfı miras alındığından dolayı, API dokümanı, değerlerin string tipinde olması gerektiğini anlayabilecek ve doğru bir şekilde işlenecektir.

Sonrasında, sınıf içerisinde, mevcut ve geçerli değerler olacak olan sabit değerli özelliklerini oluşturalım:

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

İpucu

Merak ediyorsanız söyleyeyim, "AlexNet", "ResNet" ve "LeNet" isimleri Makine Öğrenmesi modellerini temsil eder.

Bir Yol Parametresi Tanımlayalım

Sonrasında, yarattığımız enum sınıfını (ModelName) kullanarak tip belirteci aracılığıyla bir yol parametresi oluşturalım:

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

Dokümana Göz Atalım

Yol parametresi için mevcut değerler ön tanımlı olduğundan dolayı, interaktif döküman onları güzel bir şekilde gösterebilir:

Python Enumerationları ile Çalışmak

Yol parametresinin değeri bir enumeration üyesi olacaktır.

Enumeration Üyelerini Karşılaştıralım

Parametreyi, yarattığınız enum olan ModelName içerisindeki enumeration üyesi ile karşılaştırabilirsiniz:

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

Enumeration Değerini Edinelim

model_name.value veya genel olarak your_enum_member.value tanımlarını kullanarak (bu durumda bir str olan) gerçek değere ulaşabilirsiniz:

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

İpucu

"lenet" değerine ModelName.lenet.value tanımı ile de ulaşabilirsiniz.

Enumeration Üyelerini Döndürelim

JSON gövdesine (örneğin bir dict) gömülü olsalar bile yol operasyonundaki enum üyelerini döndürebilirsiniz.

Bu üyeler istemciye iletilmeden önce kendilerine karşılık gelen değerlerine (bu durumda string) dönüştürüleceklerdir:

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

İstemci tarafında şuna benzer bir JSON yanıtı ile karşılaşırsınız:

{
  "model_name": "alexnet",
  "message": "Deep Learning FTW!"
}

Yol İçeren Yol Parametreleri

Farz edelim ki elinizde /files/{file_path} isminde bir yol operasyonu var.

Fakat file_path değerinin home/johndoe/myfile.txt gibi bir yol barındırmasını istiyorsunuz.

Sonuç olarak, oluşturmak istediğin URL /files/home/johndoe/myfile.txt gibi bir şey olacaktır.

OpenAPI Desteği

Test etmesi ve tanımlaması zor senaryolara sebebiyet vereceğinden dolayı OpenAPI, yol barındıran yol parametrelerini tanımlayacak bir çözüm sunmuyor.

Ancak bunu, Starlette kütüphanesinin dahili araçlarından birini kullanarak FastAPI'da gerçekleştirebilirsiniz.

Parametrenin bir yol içermesi gerektiğini belirten herhangi bir doküman eklemememize rağmen dokümanlar yine de çalışacaktır.

Yol Dönüştürücü

Direkt olarak Starlette kütüphanesinden gelen bir opsiyon sayesinde aşağıdaki gibi yol içeren bir yol parametresi bağlantısı tanımlayabilirsiniz:

/files/{file_path:path}

Bu durumda, parametrenin adı file_path olacaktır ve son kısım olan :path kısmı, parametrenin herhangi bir yol ile eşleşmesi gerektiğini belirtecektir.

Böylece şunun gibi bir kullanım yapabilirsiniz:

from fastapi import FastAPI

app = FastAPI()


@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
    return {"file_path": file_path}

İpucu

Parametrenin başında /home/johndoe/myfile.txt yolunda olduğu gibi (/) işareti ile birlikte kullanmanız gerektiği durumlar olabilir.

Bu durumda, URL, files ile home arasında iki eğik çizgiye (//) sahip olup /files//home/johndoe/myfile.txt gibi gözükecektir.

Özet

FastAPI ile kısa, sezgisel ve standart Python tip tanımlamaları kullanarak şunları elde edersiniz:

  • Editör desteği: hata denetimi, otomatik tamamlama, vb.
  • Veri "dönüştürme"
  • Veri doğrulama
  • API tanımlamaları ve otomatik dokümantasyon

Ve sadece, bunları bir kez tanımlamanız yeterli.

Diğer frameworkler ile karşılaştırıldığında (ham performans dışında), üstte anlatılan durum muhtemelen FastAPI'ın göze çarpan başlıca avantajıdır.