FastAPI adalah framework web Python modern untuk membangun REST API dengan cepat, aman, dan performa tinggi. Dibangun di atas Starlette dan Pydantic, FastAPI memanfaatkan type hint Python untuk menghasilkan validasi otomatis, serialisasi, dan dokumentasi interaktif tanpa menulis satu baris konfigurasi pun. Tidak heran framework ini dipakai tim di Netflix, Uber, Microsoft, dan banyak startup.
Di tutorial ini kamu tidak hanya sekadar "membuat API hello world". Kamu akan membangun REST API CRUD yang utuh — dari path & query parameter, request body dengan validasi Pydantic, status code, error handling, dokumentasi otomatis, dependency injection, sampai testing. Semua kode bisa langsung dijalankan dan dipraktikkan.
Istilah kunci: Endpoint = alamat URL yang bisa dipanggil klien (misal /items). Request = data yang dikirim klien. Response = balasan server (biasanya JSON). REST = gaya desain API yang memakai method HTTP (GET, POST, PUT, DELETE) untuk operasi baca, buat, ubah, dan hapus.
Sebelum mulai, pastikan kamu sudah punya:
- Python 3.8 atau lebih baru (cek dengan
python3 --version). FastAPI modern menyarankan Python 3.10+. - Kemampuan dasar Python: fungsi, tipe data, dan type hint sederhana.
- Terminal/command line untuk menjalankan perintah.
Buat direktori proyek baru dan aktifkan virtual environment agar dependensi terisolasi per proyek. Ini kebiasaan wajib developer Python.
# Buat direktori proyek dan masuk ke dalamnya
mkdir belajar-fastapi && cd belajar-fastapi
# Buat dan aktifkan virtual environment
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Pasang FastAPI dan Uvicorn (server ASGI)
pip install fastapi uvicorn
FastAPI adalah framework-nya, sedangkan Uvicorn adalah server ASGI yang menjalankan aplikasi FastAPI dan mendukung operasi asinkron (async/await).
Buat file main.py dengan aplikasi paling sederhana. Perhatikan bahwa setiap endpoint adalah sebuah fungsi Python biasa yang dihiasi decorator seperti @app.get(...).
# main.py
from fastapi import FastAPI
# Membuat instance aplikasi
app = FastAPI(
title="API Belajar FastAPI",
description="Contoh REST API dari tutorial BengkelKode",
version="1.0.0",
)
@app.get("/")
def baca_root():
return {"pesan": "Halo, dunia!"}
Jalankan server dengan --reload agar otomatis restart setiap kali kode berubah:
uvicorn main:app --reload
Penjelasan singkat:
FastAPI()— membuat objek aplikasi.@app.get("/")— mendaftarkan endpoint untuk methodGETdi path/.- Nilai yang di-
returnotomatis diubah menjadi JSON.
Buka http://127.0.0.1:8000/docs di browser — kamu akan melihat dokumentasi interaktif Swagger UI yang dibuat otomatis. Coba panggil endpoint GET / langsung dari sana.
Path parameter adalah bagian dari URL itu sendiri, sedangkan query parameter dikirim setelah tanda ?. Keduanya di-declare sebagai argumen fungsi — FastAPI otomatis membaca tipe datanya dan melakukan validasi.
from fastapi import FastAPI
app = FastAPI()
# Path parameter: diambil dari URL, contoh /users/42
@app.get("/users/{user_id}")
def ambil_user(user_id: int):
return {"user_id": user_id, "tipe": type(user_id).__name__}
# Query parameter: diambil dari ?q=...&limit=..., contoh /cari?q=laptop&limit=5
@app.get("/cari")
def cari(q: str = "", limit: int = 10):
return {"query": q, "limit": limit}
Coba akses /users/42 — FastAPI otomatis mengubah "42" (string di URL) menjadi int 42. Kalau kamu akses /users/abc, FastAPI akan mengembalikan error validasi 422 beserta detailnya.
Kenapa type hint penting? Karena FastAPI memakainya untuk: (1) validasi otomatis, (2) konversi tipe, (3) dokumentasi OpenAPI, dan (4) autocomplete di editor. Ini inti dari desain FastAPI.
Saat klien mengirim data lewat POST/PUT, body-nya dideklarasikan sebagai model Pydantic. Pydantic akan memvalidasi dan mengubah data mentah menjadi objek Python yang aman.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
# Model / skema data (ini sekaligus jadi dokumentasi)
class Item(BaseModel):
nama: str
harga: float
tersedia: bool = True # field dengan nilai default
@app.post("/items/")
def buat_item(item: Item):
# `item` sudah menjadi objek Python yang tervalidasi
return {"pesan": "Item berhasil dibuat", "item": item}
Kalau klien mengirim {"nama": 123} (nama harusnya string) atau tidak mengirim harga, FastAPI menolak dengan status 422 dan pesan error yang jelas — tanpa kamu menulis logika validasi apa pun.
Kesalahan umum pemula: lupa menambahkan type hint pada parameter body, sehingga FastAPI menganggapnya query parameter. Pastikan model body kamu dipakai sebagai anotasi tipe argumen fungsi.
Sekarang gabungkan semuanya menjadi API CRUD yang utuh. Untuk contoh ini kita pakai dict sebagai "database" sementara agar mudah dipahami — nanti tinggal diganti PostgreSQL/MySQL/SQLite.
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
nama: str
harga: float
# Penyimpanan sementara di memori
db: dict[int, dict] = {}
id_berikutnya = 1
@app.get("/items/")
def daftar_item():
return [{"id": i, **data} for i, data in db.items()]
@app.post("/items/", status_code=status.HTTP_201_CREATED)
def buat_item(item: Item):
global id_berikutnya
db[id_berikutnya] = item.model_dump()
hasil = {"id": id_berikutnya, **item.model_dump()}
id_berikutnya += 1
return hasil
@app.get("/items/{item_id}")
def ambil_item(item_id: int):
if item_id not in db:
raise HTTPException(status_code=404, detail="Item tidak ditemukan")
return {"id": item_id, **db[item_id]}
@app.put("/items/{item_id}")
def perbarui_item(item_id: int, item: Item):
if item_id not in db:
raise HTTPException(status_code=404, detail="Item tidak ditemukan")
db[item_id] = item.model_dump()
return {"id": item_id, **db[item_id]}
@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
def hapus_item(item_id: int):
if item_id not in db:
raise HTTPException(status_code=404, detail="Item tidak ditemukan")
del db[item_id]
Perhatikan pola CRUD di atas:
GET /items/— membaca semua item.POST /items/— membuat item baru (status201).GET /items/{id}— membaca satu item.PUT /items/{id}— memperbarui item.DELETE /items/{id}— menghapus item (status204).
HTTP status code memberitahu klien hasil permintaannya. Beberapa yang paling sering dipakai: 200 (sukses), 201 (berhasil dibuat), 204 (sukses tanpa konten), 400 (request salah), 404 (tidak ditemukan), 422 (gagal validasi), dan 500 (error server).
Untuk error, gunakan HTTPException — FastAPI otomatis mengubahnya menjadi respons JSON yang rapi:
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/items/{item_id}")
def ambil_item(item_id: int):
if item_id <= 0:
raise HTTPException(
status_code=400,
detail="ID harus bilangan positif",
)
# ... logika pencarian item ...
raise HTTPException(status_code=404, detail="Item tidak ditemukan")
Untuk error yang tidak kamu tangani sendiri, kamu bisa menambah exception handler global agar seluruh API mengembalikan format yang konsisten.
Pydantic menyediakan banyak validasi siap pakai lewat Field, constraint tipe, dan bahkan custom validator. Ini membuat data yang masuk ke sistem selalu bersih sejak di pintu masuk.
from fastapi import FastAPI
from pydantic import BaseModel, Field, EmailStr
app = FastAPI()
class Pengguna(BaseModel):
nama: str = Field(..., min_length=3, max_length=50)
email: EmailStr # perlu `pip install email-validator`
umur: int = Field(..., ge=18, le=100) # >= 18 dan <= 100
@app.post("/pengguna/")
def buat_pengguna(p: Pengguna):
return p
Constraint umum yang tersedia: min_length, max_length, ge (≥), gt (>), le (≤), lt (<), regex, dan tipe khusus seperti EmailStr, HttpUrl, UUID4.
Untuk aturan yang lebih kompleks, gunakan dekorator @field_validator di dalam model Pydantic — misalnya memastikan nilai tanggal_selesai selalu setelah tanggal_mulai.
Dengan response_model, kamu bisa memisahkan model input dan model output. Ini berguna untuk menyembunyikan field sensitif (misal password) dan menjaga kontrak API tetap konsisten.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class PenggunaDB(BaseModel):
nama: str
email: str
password_hash: str # jangan sampai bocor ke klien
class PenggunaPublik(BaseModel):
nama: str
email: str
@app.get("/pengguna/{user_id}", response_model=PenggunaPublik)
def ambil_pengguna(user_id: int):
# Return data lengkap, tapi FastAPI hanya mengirim field PenggunaPublik
return {"nama": "Budi", "email": "budi@example.com", "password_hash": "xyz"}
Dokumentasi interaktif di /docs (Swagger UI) dan /redoc (ReDoc) dibangun otomatis dari type hint, model Pydantic, dan response_model. Schema OpenAPI-nya bisa diakses di /openapi.json — inilah yang membuat FastAPI sangat disukai untuk kolaborasi tim.
Dependency injection lewat Depends memungkinkan kamu memakai ulang logika umum — seperti autentikasi, koneksi database, atau validasi header — di banyak endpoint tanpa menulis ulang kode.
from fastapi import FastAPI, Depends, Header, HTTPException
app = FastAPI()
def cek_api_key(x_api_key: str = Header(None)):
"""Dependency: memvalidasi API key dari header."""
if x_api_key != "rahasia-123":
raise HTTPException(status_code=401, detail="API key salah")
return x_api_key
@app.get("/data-rahasia/")
def data_rahasia(kunci: str = Depends(cek_api_key)):
return {"pesan": "Akses diberikan", "kunci": kunci}
Sekarang endpoint /data-rahasia/ otomatis menolak request tanpa header x-api-key: rahasia-123. Kamu bisa menempelkan dependency yang sama ke endpoint lain cukup dengan menambah parameter Depends(cek_api_key).
Saat API bertumbuh, jangan taruh semua endpoint di satu main.py. Pecah ke beberapa router agar kode tetap terorganisir.
# routers/items.py
from fastapi import APIRouter
# Semua endpoint di router ini otomatis diberi prefix /items
router = APIRouter(prefix="/items", tags=["items"])
@router.get("/")
def daftar_item():
return [{"nama": "Laptop", "harga": 15000000}]
@router.get("/{item_id}")
def ambil_item(item_id: int):
return {"id": item_id, "nama": "Laptop", "harga": 15000000}
# main.py
from fastapi import FastAPI
from routers.items import router as items_router
app = FastAPI()
app.include_router(items_router)
# Struktur direktori yang disarankan:
# belajar-fastapi/
# ├── main.py
# ├── routers/
# │ ├── __init__.py
# │ └── items.py
# ├── models.py # model Pydantic
# ├── schemas.py # skema request/response
# └── test_main.py # pengujian
FastAPI menyediakan TestClient sehingga kamu bisa menguji endpoint tanpa menjalankan server sungguhan. Ini penting agar API tetap stabil saat diubah.
# test_main.py
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_baca_root():
resp = client.get("/")
assert resp.status_code == 200
assert resp.json() == {"pesan": "Halo, dunia!"}
def test_buat_dan_ambil_item():
# Buat item baru
resp = client.post("/items/", json={"nama": "Mouse", "harga": 250000})
assert resp.status_code == 201
item_id = resp.json()["id"]
# Ambil kembali item tersebut
resp = client.get(f"/items/{item_id}")
assert resp.status_code == 200
assert resp.json()["nama"] == "Mouse"
def test_item_tidak_ada():
resp = client.get("/items/99999")
assert resp.status_code == 404
pip install pytest httpx
pytest test_main.py -v
Selamat! Kamu sudah membangun REST API FastAPI yang lengkap: path & query parameter, request body dengan validasi Pydantic, CRUD penuh, status code, error handling, response model, dokumentasi otomatis, dependency injection, struktur project yang rapi, dan testing. Ini fondasi yang sama dengan yang dipakai produksi di dunia nyata.
Langkah berikutnya yang disarankan: (1) ganti database in-memory dengan SQLite/PostgreSQL lewat SQLAlchemy atau SQLModel, (2) tambah autentikasi JWT, (3) pasang CORS, (4) deploy ke VPS/Render/Railway, dan (5) buat pipeline CI/CD untuk menjalankan test otomatis.
Mulai dari tutorial ini, kamu bisa langsung eksperimen: tambah field baru, buat endpoint pencarian, atau integrasikan dengan database. Dokumentasi resmi FastAPI di fastapi.tiangolo.com adalah referensi terbaik untuk melanjutkan.
BengkelKode