Mengubah auto-docs FastAPI menjadi dokumentasi produksi yang lengkap: metadata OpenAPI, tags untuk mengorganisasi endpoint, deskripsi dan parameter yang jelas, response docs dengan contoh, serta pembatasan schema.

Salah satu alasan kalian memilih FastAPI di episode 1 adalah auto-docs — dokumentasi yang lahir dari kode. Di episode ini kita naikkan level: bukan sekadar "docs yang ada", tapi docs yang layak dibaca tim dan dipakai sebagai kontrak. Dokumentasi FastAPI bisa disesuaikan sampai ke detail terkecil, dan hasilnya adalah aset API yang nyata.
Mengapa episode ini penting? Dokumentasi yang buruk membuat tiap pertanyaan "bagaimana cara pakai endpoint ini?" berakhir di chat pribadi — menyedot waktu. Dokumentasi yang baik membuat klien bisa integrasi tanpa bertanya. Perbedaannya sering hanya beberapa metadata di kode.
FastAPI(...) menerima metadata yang muncul di /docs dan /redoc:
from fastapi import FastAPI
app = FastAPI(
title="API Toko",
description="Backend toko online: item, pesanan, dan user. "
"Autentikasi via OAuth2 password flow (JWT).",
version="2.1.0",
contact={
"name": "Tim Backend",
"email": "backend@example.com",
},
license_info={
"name": "MIT",
"url": "https://opensource.org/licenses/MIT",
},
)description mendukung Markdown — digunakan ReDoc untuk render halaman yang rapi.contact dan license_info memenuhi ekspektasi API publik yang serius.version menandai versi API — sinkronkan dengan strategi versioning episode 20.Saat aplikasi tumbuh, endpoint harus dikelompokkan. Tags melakukan itu:
from fastapi import FastAPI
app = FastAPI(
tags_metadata=[
{
"name": "items",
"description": "Manajemen produk toko.",
},
{
"name": "orders",
"description": "Pemrosesan dan status pesanan.",
},
],
)
@app.get("/items/", tags=["items"])
def list_items() -> dict:
return {"items": []}
@app.post("/orders/", tags=["orders"])
def create_order() -> dict:
return {"order": "created"}Di Swagger UI, endpoint tampil dalam grup yang bisa dilipat; di OpenAPI, tag menjadi bagian struktur schema. Saat aplikasi memakai banyak router (pola episode 22), tag menjaga docs tetap terorganisasi meski kode tersebar.
Tip
Aturan satu endpoint satu tag yang utama — tag tambahan hanya jika benar-benar lintas domain. Terlalu banyak tag membuat docs sama berantakannya dengan tanpa tag sama sekali.
Kualitas dokumentasi naik drastis hanya dari docstring dan parameter deskripsi:
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/{item_id}", tags=["items"])
def get_item(
item_id: int = Query(description="ID unik item", ge=1),
include_deleted: bool = Query(
default=False,
description="Sertakan item yang sudah dihapus",
),
) -> dict:
"""Mengambil detail satu item.
Mengembalikan nama, harga, dan stok item. Jika item tidak
ada, mengembalikan 404.
- `include_deleted=true` untuk audit
"""
return {"item_id": item_id, "include_deleted": include_deleted}Docstring menjadi description endpoint di docs; Query(description=...) menjadi deskripsi parameter. Pembaca docs sekarang tahu persis apa yang diharapkan — tanpa membaca kode.
FastAPI bisa mendokumentasikan tiap status code yang mungkin dikembalikan — termasuk contoh response:
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
from app.schemas import ItemOut
@app.get(
"/items/{item_id}",
response_model=ItemOut,
responses={
404: {
"description": "Item tidak ditemukan",
"content": {
"application/json": {
"example": {
"detail": "Item tidak ditemukan",
"code": "NOT_FOUND",
}
}
},
}
},
)
def get_item(item_id: int) -> ItemOut:
if item_id > 100:
raise HTTPException(status_code=404, detail="Item tidak ditemukan")
return ItemOut(id=item_id, name="item", price=10.0)Sekarang docs menampilkan contoh response 404 yang persis seperti yang klien akan terima — format error dari episode 17 terdokumentasi eksplisit. Ini membuat klien bisa menulis error handling dengan yakin.
Important
responses={...} mendokumentasikan error path yang sengaja dibuat. Jangan lupa mendokumentasikan 422 (validasi) dan 401 (auth) juga — tiga error itu hampir selalu ada di API nyata dan membuat klien menebak-nebak jika tidak tertulis.
Di Swagger UI, tombol "Example Value" pada body request bisa diisi nilai nyata:
from pydantic import BaseModel, Field
class ItemCreate(BaseModel):
name: str = Field(
...,
min_length=1,
max_length=100,
examples=["Keyboard Mekanik"],
)
price: float = Field(..., gt=0, examples=[499000.0])Field examples=[...] (bukan example tunggal, sesuai OpenAPI 3.1) membuat body di docs sudah terisi contoh yang valid — klien bisa langsung klik "Try it out" tanpa menebak format.
Ingat UserInternal di episode 7? Schema yang diekspos ke OpenAPI ikut membatasi apa yang terlihat:
@app.get(
"/users/{user_id}",
response_model=UserPublic,
tags=["users"],
)
def get_user(user_id: int) -> UserInternal:
return get_user_internal(user_id)FastAPI mendaftarkan ke OpenAPI hanya schema yang muncul di path operation — UserInternal tidak pernah terekspos, sehingga docs (dan siapa pun yang membacanya) hanya melihat field publik. Ini cara lain menjaga boundary keamanan yang kita bangun di episode 7.
| Pitfall | Solusi |
|---|---|
| Metadata kosong | Isi title, description, version |
| Endpoint tanpa deskripsi | Tulis docstring |
example vs examples | OpenAPI 3.1 memakai examples |
| Schema internal terlihat | Hanya response_model public di endpoint |
| Docs tidak mencerminkan error nyata | Dokumentasikan semua status di responses |
Inti yang harus dibawa pulang:
title, description, contact) memanusiakan docs.responses={...} mendokumentasikan error + contoh — termasuk format error episode 17.examples di Field membuat Swagger "Try it out" langsung berguna.Di episode 22 selanjutnya kita akan membahas microservices & async architecture — memecah aplikasi menjadi service, komunikasi antar service dengan HTTP dan message broker (RabbitMQ/Kafka), serta pola event-driven yang menghubungkan semuanya!