Lewati ke isi

Parameter Path

"parameter" atau "variabel" path didefinisikan dengan sintaksis Python format string:

from fastapi import FastAPI

app = FastAPI()


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

Nilai parameter path item_id akan dikirim ke fungsi sebagai argument item_id:

Jika anda menjalankan contoh berikut dan kunjungi to http://127.0.0.1:8000/items/foo, anda akan melihat respon:

{"item_id":"foo"}

Parameter path dengan tipe data

Tipe data di parameter path bisa didefinisikan di dalam fungsi, menggunakan anotasi tipe data standar Python:

from fastapi import FastAPI

app = FastAPI()


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

Di kondisi ini item_id didefinisikan sebagai int.

/// periksa

Penyunting kode anda bisa membantu periksa di dalam fungsi seperti pemeriksaan kesalahan, kelengkapan kode, dll.

///

Konversi data

Jika contoh berikut dijalankan dan diakses browser melalui http://127.0.0.1:8000/items/3, anda akan melihat respon:

{"item_id":3}

/// periksa

Perhatikan nilai fungsi yang diterima (dan dihasilkan) adalah 3, sebagai int di Python, dan bukan string "3".

Sehingga dengan deklarasi tipe data FastAPI memberikan request otomatis "parsing".

///

Validasi Data

Tetapi jika di browser anda akses http://127.0.0.1:8000/items/foo, anda akan melihat pesan kesalahan HTTP:

{
  "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"
    }
  ]
}

Karena parameter path item_id bernilai "foo" yang bukan tipe data int.

Kesalahan yang sama akan muncul jika menggunakan float daripada int, seperti di: http://127.0.0.1:8000/items/4.2

/// periksa

Dengan deklarasi tipe data Python, FastAPI melakukan validasi data.

Perhatikan kesalahan tersebut juga menjelaskan validasi apa yang tidak sesuai.

Validasi ini sangat membantu ketika developing dan debugging kode yang berhubungan dengan API anda.

///

Dokumentasi

Ketika anda membuka browser di http://127.0.0.1:8000/docs, anda melihat dokumentasi API interaktif otomatis berikut:

/// periksa

Dengan deklarasi tipe data Python yang sama, FastAPI membuat dokumentasi interaktif otomatis (terintegrasi Swagger UI).

Perhatikan parameter path dideklarasikan sebagai integer.

///

Keuntungan basis-standar, dokumentasi alternatif

Karena skema yang dibuat berasal dari standar OpenAPI, maka banyak tools lain yang kompatibel.

Sehingga FastAPI menyediakan dokumentasi alternatif (menggunakan ReDoc), yang bisa diakses di http://127.0.0.1:8000/redoc:

Cara yang sama untuk menggunakan tools kompatibel lainnya. Termasuk tools membuat kode otomatis untuk banyak bahasa.

Pydantic

Semua validasi data dikerjakan di belakang layar oleh Pydantic, sehingga anda mendapatkan banyak kemudahan. Anda juga tahu proses ini ditangani dengan baik.

Anda bisa mendeklarasikan tipe data dengan str, float, bool dan banyak tipe data kompleks lainnya.

Beberapa tipe di atas akan dibahas pada bab berikutnya tutorial ini.

Urutan berpengaruh

Ketika membuat operasi path, anda bisa menghadapi kondisi dimana path nya sudah tetap.

Seperti /users/me, misalkan ini untuk mendapatkan data user yang sedang aktif.

Kemudian anda bisa memiliki path /users/{user_id} untuk mendapatkan data user tertentu melalui user ID.

karena operasi path dievaluasi melalui urutan, anda harus memastikan path untuk /users/me dideklarasikan sebelum /user/{user_id}:

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}

Sebaliknya, path /users/{user_id} juga akan sesuai dengan /users/me, "menganggap" menerima parameter user_id dengan nilai "me".

Serupa, anda juga tidak bisa mendefinisikan operasi path:

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"]

Path pertama akan selalu digunakan karena path sesuai dengan yang pertama.

Nilai terdefinisi

Jika ada operasi path yang menerima parameter path, tetapi anda ingin nilai valid parameter path sudah terdefinisi, anda bisa menggunakan standar Python Enum.

Membuat class Enum

Import Enum dan buat sub-class warisan dari str dan Enum.

Dengan warisan dari str dokumen API mengetahui nilai nya harus berjenis string supaya bisa digunakan dengan benar.

Kemudian buat atribut class dengan nilai tetap string yang benar:

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"}

/// tips

"AlxexNet", "ResNet", dan "LeNet" adalah nama model Machine Learning.

///

Mendeklarasikan parameter path

Kemudian buat parameter path dengan tipe anotasi menggunakan class enum dari (ModelName)

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"}

Periksa dokumentasi

Karena nilai yang tersedia untuk parameter path telah terdefinisi, dokumen interatik bisa memunculkan:

Bekerja dengan enumarasi Python

Nilai parameter path akan menjadi anggota enumerasi.

Membandingkan anggota enumerasi

Anda bisa membandingkan parameter path dengan anggota enumerasi di enum ModelName yang anda buat:

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"}

Mendapatkan nilai enumerasi

Anda bisa mendapatkan nilai (str dalam kasus ini) menggunakan model_name.value, atau secara umum anggota_enum_anda.value:

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"}

/// tips

Anda bisa mengakses nilai "lenet" dnegan ModelName.lenet.value.

///

Menghasilkan anggota enumerasi

Anda bisa menghasilkan anggota enumerasi dari operasi path bahkan di body JSON bersarang (contoh dict).

They will be converted to their corresponding values (strings in this case) before returning them to the client:

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"}

Klien akan mendapatkan respon JSON seperti berikut:

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

Parameter path berisi path

Misalkan terdapat operasi path dengan path /files/{file_path}.

Tetapi anda memerlukan file_path itu berisi path, seperti like home/johndoe/myfile.txt.

Sehingga URL untuk file tersebut akan seperti: /files/home/johndoe/myfile.txt.

Dukungan OpenAPI

OpenAPI tidak bisa mendeklarasikan parameter path berisi path di dalamnya, karena menyebabkan kondisi yang sulit ditest dan ddiefinisi OpenAPI doesn't support a way to declare a path parameter to contain a path inside, as that could lead to scenarios that are difficult to test and define.

Nevertheless, you can still do it in FastAPI, using one of the internal tools from Starlette.

And the docs would still work, although not adding any documentation telling that the parameter should contain a path.

Path convertor

Using an option directly from Starlette you can declare a path parameter containing a path using a URL like:

/files/{file_path:path}

In this case, the name of the parameter is file_path, and the last part, :path, tells it that the parameter should match any path.

So, you can use it with:

from fastapi import FastAPI

app = FastAPI()


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

Tip

You could need the parameter to contain /home/johndoe/myfile.txt, with a leading slash (/).

In that case, the URL would be: /files//home/johndoe/myfile.txt, with a double slash (//) between files and home.

Recap

With FastAPI, by using short, intuitive and standard Python type declarations, you get:

  • Editor support: error checks, autocompletion, etc.
  • Data "parsing"
  • Data validation
  • API annotation and automatic documentation

And you only have to declare them once.

That's probably the main visible advantage of FastAPI compared to alternative frameworks (apart from the raw performance).