Belajar FastAPI - Request Body & Forms
Episode 6 of 28

Belajar FastAPI - Request Body & Forms

Menguasai berbagai cara menerima input di FastAPI: request body berbasis Pydantic model, parameter body tunggal, embed untuk struktur JSON tertentu, kombinasi path, query dan body sekaligus, serta Form data untuk aplikasi x-www-form-urlencoded.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 5 kita membangun Pydantic models dengan validasi penuh, sekarang kita pelajari cara-cara FastAPI menerima data dari klien. Selama ini kita hanya memakai satu model per request — padahal di dunia nyata, satu endpoint sering menerima kombinasi: parameter di path, filter di query, dan data kompleks di body.

Mengapa episode ini penting? Karena kegagalan memahami cara kerja body akan menghasilkan API yang sulit dipakai klien — misalnya struktur JSON yang tidak intuitif, atau endpoint yang menolak form login padahal frontend mengirimnya. FastAPI memberi kontrol penuh atas bentuk request body; kita pelajari tiap opsi sekarang.

Body dengan Pydantic Model: Bentuk Paling Umum

Cara paling idiomatis — deklarasikan satu parameter bertipe model, dan FastAPI mengekspektasi seluruh body sesuai model tersebut:

Pythonapp/main.py - body model tunggal
from fastapi import FastAPI
from app.schemas import ItemCreate
 
app = FastAPI()
 
 
@app.post("/items/")
def create_item(item: ItemCreate) -> dict:
    return {"name": item.name, "price": item.price}

Klien harus mengirim JSON yang persis bentuk ItemCreate:

Request body
{"name": "Keyboard", "price": 500000}

Jika klien mengirim field tambahan — {"name": "Keyboard", "price": 500000, "stock": 5} — perilaku default Pydantic 2.x adalah mengabaikannya (ignore extra). Ini sering mengejutkan, jadi pastikan kalian tahu: atur model_config = ConfigDict(extra="forbid") pada model jika ingin menolak field tak dikenal.

Kombinasi Path, Query, dan Body

Satu endpoint bisa menerima ketiga sumber sekaligus. FastAPI menentukan asal parameter dari tipe dan deklarasinya:

PythonKombinasi path, query, body
@app.put("/items/{item_id}")
def update_item(
    item_id: int,          # dari path
    q: str | None = None,  # dari query
    item: ItemCreate,      # dari body
) -> dict:
    return {"item_id": item_id, "q": q, "item": item.model_dump()}

Aturannya konsisten dari episode 4: parameter yang namanya cocok dengan {kurung_kurawal} di path → path param; parameter primitif lainnya → query param; parameter bertipe Pydantic model → body. Tidak ada konflik karena tipe menentukan asal.

Tip

Urutan deklarasi bebas, tapi untuk keterbacaan ikuti konvensi: path param, lalu query, lalu body — persis seperti URL-nya: /path?query + body.

Single Body Parameter: Tanpa Membungkus

FastAPI juga menerima parameter primitif sebagai body langsung:

PythonSingle body parameter
from fastapi import Body
 
 
@app.put("/items/")
def create_item(name: str = Body(...)) -> dict:
    return {"name": name}

Klien mengirim body "Keyboard" (JSON string), bukan {"name": "Keyboard"}. Gunakan pola ini hanya saat memang dibutuhkan — untuk API publik, bentuk objek hampir selalu lebih jelas dan lebih mudah dievolusi.

Embed: Mengontrol Struktur JSON

Default FastAPI: ketika sebuah fungsi punya satu parameter bertipe model, seluruh body dipetakan langsung ke model — body {"name": ...} cocok dengan item: ItemCreate. Tapi ketika ada dua parameter bertipe model, FastAPI butuh cara membedakan keduanya, dan di sinilah Body(embed=True) bekerja:

PythonBody embed untuk dua model
from fastapi import FastAPI, Body
from app.schemas import ItemCreate, Tag
 
app = FastAPI()
 
 
@app.post("/items/with-tag/")
def create_with_tag(
    item: ItemCreate = Body(embed=True),
    tag: Tag = Body(embed=True),
) -> dict:
    return {"item": item.model_dump(), "tag": tag.model_dump()}

Body yang diharapkan klien:

Request body dengan embed
{
  "item": {"name": "Keyboard", "price": 500000},
  "tag": {"name": "input"}
}

embed=True membungkus tiap parameter body di bawah kunci-nya sendiri. Tanpa embed, FastAPI tidak bisa membedakan dua body — ini salah satu detail FastAPI yang paling sering bikin pusing pemula.

Note

Aturan cepat: satu parameter body → default langsung (tanpa embed). Dua atau lebih parameter body → tiap parameter perlu Body(embed=True). Kalau kalian melihat schema body aneh di /docs, kemungkinan besar masalahnya ada di sini.

Form Data: x-www-form-urlencoded

FastAPI menangani form HTML dan data application/x-www-form-urlencoded melalui Form. Ini penting untuk endpoint login klasik dan aplikasi yang bukan SPA:

PythonForm data dengan Form
from fastapi import FastAPI, Form
 
app = FastAPI()
 
 
@app.post("/login/")
def login(
    username: str = Form(...),
    password: str = Form(...),
) -> dict[str, str]:
    return {"username": username, "message": "login berhasil"}

Perbedaan penting yang wajib dihafal:

  • Form(...) membaca data dari body urlencoded — klien mengirim username=...&password=....
  • Untuk memakai Form, package python-multipart harus diinstall: pip install python-multipart — tanpa itu, FastAPI error saat import.
Uji endpoint form dengan curl
curl -s -X POST http://127.0.0.1:8000/login/ \
  -d "username=budi&password=rahasia"

Warning

Jangan mengirim data melalui Form untuk payload kompleks — form urlencoded hanya mendukung pasangan key-value sederhana. Untuk struktur bertingkat tetap gunakan JSON body dengan model. Dan ingat: contoh login di sini hanya demo parsing; keamanan auth yang benar dibahas di episode 12.

Pilihan Jenis Data: Ringkasan

JenisSumber dataKapan dipakai
Model / BodyJSON bodyData terstruktur, API utama
QueryURL ?key=valueFilter, pagination
PathSegmen URLIdentitas resource
Formapplication/x-www-form-urlencodedForm HTML, login klasik
Header / CookieHTTP header / cookieMetadata, token (episode 12)

Common Pitfalls

PitfallSolusi
Dua body model tanpa embed=TrueSchema body aneh di /docs; tambahkan embed=True
Form tanpa python-multipartImport error; install python-multipart
Field ekstra diam-diam diabaikanConfigDict(extra="forbid") pada model
Mengirim JSON ke endpoint FormGanti klien: kirim x-www-form-urlencoded

Penutup

Inti yang harus dibawa pulang:

  • Parameter bertipe model = request body; primitif = query; cocok dengan path = path param.
  • Satu body → langsung; dua atau lebih body → Body(embed=True).
  • Form untuk urlencoded; butuh python-multipart.
  • Header/Cookie tersedia sebagai jenis data lain yang kita pakai di episode 12.

Di episode 7 selanjutnya kita akan membahas response model & status code — memastikan bentuk output tetap terjaga dengan response_model, memakai status code yang tepat untuk tiap operasi, menambahkan response headers, sampai membangun custom response. Output yang rapi adalah wajah API kalian di depan klien!

Belajar FastAPI - Request Body & Forms | Belajar FastAPI