Menguasai path operations GET, POST, PUT dan DELETE, path parameters dengan validasi tipe dan constraint, query parameters dengan nilai default, hingga aturan urutan parameter dan path yang sering menjebak pemula.

Setelah di episode 3 kalian berhasil menjalankan aplikasi FastAPI pertama dan melihat auto-docs bekerja, sekarang kita naik satu level: routing lengkap. REST API dibangun dari operasi standar terhadap resource — ini yang membedakan aplikasi yang hanya menampilkan teks dengan aplikasi yang benar-benar melayani data.
Mengapa episode ini penting? Karena hampir semua bug routing yang ditemukan di produksi — endpoint yang tidak ketemu, parameter yang salah tipe, atau path yang bentrok — berakar pada kurangnya pemahaman tiga hal yang akan kita bahas: HTTP methods, path vs query parameters, dan urutan deklarasi.
FastAPI menyediakan dekorator untuk setiap HTTP method. Pola umum pada resource items:
from fastapi import FastAPI
app = FastAPI()
ITEMS = {1: "Keyboard", 2: "Mouse"}
@app.get("/items/{item_id}")
def get_item(item_id: int) -> dict:
return {"item_id": item_id, "name": ITEMS[item_id]}
@app.post("/items/")
def create_item(name: str) -> dict:
new_id = max(ITEMS) + 1
ITEMS[new_id] = name
return {"item_id": new_id, "name": name}
@app.put("/items/{item_id}")
def update_item(item_id: int, name: str) -> dict:
ITEMS[item_id] = name
return {"item_id": item_id, "name": name}
@app.delete("/items/{item_id}")
def delete_item(item_id: int) -> dict[str, bool]:
del ITEMS[item_id]
return {"ok": True}Perhatikan pola semantiknya:
| Method | Tujuan | Status sukses ideal |
|---|---|---|
GET | Membaca resource | 200 |
POST | Membuat resource baru | 201 |
PUT | Mengganti resource utuh | 200 |
DELETE | Menghapus resource | 204 |
Status code akan kita bahas detail di episode 7 — di episode ini kita fokus pada pemetaan URL dan parameter.
Tip
Gunakan trailing slash konsisten: FastAPI menganggap /items dan /items/ sama (redirect 307), tapi lebih baik memilih satu gaya dan menaatinya di seluruh aplikasi. Contoh series ini memakai trailing slash pada koleksi: /items/.
Path parameter adalah bagian dari URL yang dinamis, dideklarasikan dengan kurung kurawal di string path:
@app.get("/items/{item_id}")
def get_item(item_id: int) -> dict:
return {"item_id": item_id}{item_id} di path dipasangkan dengan parameter item_id: int di fungsi. FastAPI lalu:
item_id dari URL.int — request /items/42 menghasilkan 42 bertipe int./items/abc.Urutan parameter penting di sini: FastAPI mengenali path parameter dari nama yang cocok dengan kurung kurawal di path. Semua parameter fungsi lain secara otomatis dianggap query parameter.
Query parameters adalah pasangan key=value setelah tanda ? di URL, dan dideklarasikan cukup dengan parameter fungsi biasa:
@app.get("/items/")
def list_items(skip: int = 0, limit: int = 10, q: str | None = None) -> dict:
return {"skip": skip, "limit": limit, "q": q}URL /items/?skip=0&limit=5&q=keyboard menghasilkan skip=0, limit=5, q="keyboard". Aturan yang perlu dipahami:
/items/ tanpa skip akan error 422).Tipe str | None = None (Python 3.10+) memberi tahu FastAPI bahwa parameter ini opsional dan boleh null — representasi ini adalah gaya modern yang direkomendasikan menggantikan Optional[str].
Python menuntut parameter wajib sebelum parameter berdefault. FastAPI menambahkan satu lapis aturan lagi — path parameter harus di deklarasikan lebih dulu jika ada query param opsional setelahnya. Perhatikan dua kasus:
@app.get("/users/{user_id}/items/{item_id}")
def read_user_item(
user_id: int,
item_id: int,
q: str | None = None,
) -> dict:
return {"user_id": user_id, "item_id": item_id, "q": q}Ini valid: path params (user_id, item_id) lebih dulu, lalu query param opsional (q). Yang sering menjebak adalah menaruh parameter tanpa default setelah parameter berdefault — Python sendiri akan melempar SyntaxError.
Caution
Jangan menaruh parameter wajib (tanpa default) setelah parameter opsional di fungsi yang sama. Contoh def f(a: int = 1, b: int) bukan hanya ditolak Python — ia membuat API kalian ambigu. Kalau perlu parameter wajib, deklarasikan lebih dulu.
Dari episode ini kita mulai memakai Path dan Query — objek FastAPI untuk menambahkan constraint dan metadata:
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
def get_item(
item_id: int = Path(ge=1, description="ID item, minimal 1"),
q: str | None = Query(default=None, max_length=50, description="Kata kunci"),
) -> dict:
return {"item_id": item_id, "q": q}Path(ge=1) — item_id harus >= 1, jika tidak → 422.Query(max_length=50) — q maksimal 50 karakter.Constraint ini bukan hanya dokumentasi — FastAPI menjadikannya bagian dari schema OpenAPI dan menjalankan validasinya saat runtime.
Important
Gaya modern yang direkomendasikan di FastAPI 0.141 adalah menulis constraint dalam bentuk Annotated: item_id: Annotated[int, Path(ge=1)]. Ini memisahkan tipe dari metadata dan lebih aman terhadap pola parameter weird. Di episode 8 saat membahas dependency, Annotated menjadi wajib.
| Ciri | Path parameter | Query parameter |
|---|---|---|
| Lokasi | Di dalam URL path | Setelah tanda ? |
| Contoh | /items/42 | /items/?limit=5 |
| Wajib? | Ya, selalu ada di URL | Opsional jika berdefault |
| Cocok untuk | Identitas resource | Filter, pagination, opsi |
Inti yang harus dibawa pulang:
@app.get / @app.post / @app.put / @app.delete.Path dan Query menambahkan constraint + metadata yang masuk ke OpenAPI.Di episode 5 selanjutnya kita akan membahas Pydantic models & validation — jantung validasi FastAPI. Kalian akan belajar mendefinisikan request/response schema, nested models, constraint Field, serta field_validator dan model_validator untuk aturan lintas field. Ini fondasi untuk semua episode database berikutnya!