FastAPI adalah framework Python modern untuk membangun API yang menggabungkan tiga hal yang jarang ada di satu framework: kecepatan (setara Node.js dan Go), developer experience yang luar biasa, dan dokumentasi API otomatis. Jika Anda membangun microservice untuk model ML, data processing, atau layanan Python apa pun yang perlu dikonsumsi aplikasi lain, FastAPI adalah pilihan yang sangat solid.

Mengapa FastAPI?

  • Performance — Berbasis ASGI (Starlette), performa setara Node.js berkat async I/O
  • Auto-dokumentasi — Swagger UI dan ReDoc tergenerate otomatis dari code
  • Type Safety — Validasi request/response otomatis via Pydantic v2
  • Python Type Hints — Full IDE support, autocomplete, dan error detection
  • Standards — Mengikuti OpenAPI dan JSON Schema standards

Setup dan Hello World

pip install fastapi uvicorn[standard] pydantic sqlalchemy alembic

# Jalankan server
uvicorn main:app --reload
# main.py
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI(
    title="Artikel API",
    description="Microservice untuk manajemen konten",
    version="1.0.0",
)

class PostCreate(BaseModel):
    title: str
    content: str
    status: str = "draft"

class PostResponse(BaseModel):
    id: int
    title: str
    slug: str
    status: str

@app.get("/")
async def root():
    return {"message": "API aktif"}

@app.post("/posts", response_model=PostResponse, status_code=201)
async def create_post(post: PostCreate):
    # FastAPI otomatis validasi request body
    # Dokumentasi Swagger otomatis tersedia di /docs
    return {"id": 1, "title": post.title, "slug": "generated-slug", "status": post.status}

Buka http://localhost:8000/docs — Swagger UI sudah tersedia tanpa konfigurasi apapun.

Database dengan SQLAlchemy + Async

pip install sqlalchemy[asyncio] asyncpg  # Untuk PostgreSQL
# database.py
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import DeclarativeBase, sessionmaker

DATABASE_URL = "postgresql+asyncpg://user:password@localhost/db"

engine = create_async_engine(DATABASE_URL, echo=True)
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)

class Base(DeclarativeBase):
    pass

# Dependency injection untuk session
async def get_db():
    async with AsyncSessionLocal() as session:
        try:
            yield session
            await session.commit()
        except Exception:
            await session.rollback()
            raise
# models.py
from sqlalchemy import String, Text, DateTime, func
from sqlalchemy.orm import Mapped, mapped_column
from database import Base

class Post(Base):
    __tablename__ = "posts"

    id: Mapped[int] = mapped_column(primary_key=True)
    title: Mapped[str] = mapped_column(String(255))
    slug: Mapped[str] = mapped_column(String(255), unique=True, index=True)
    content: Mapped[str] = mapped_column(Text)
    status: Mapped[str] = mapped_column(String(20), default="draft")
    created_at: Mapped[DateTime] = mapped_column(DateTime, server_default=func.now())

CRUD Endpoint Lengkap

# routers/posts.py
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from database import get_db
from models import Post
from schemas import PostCreate, PostUpdate, PostResponse

router = APIRouter(prefix="/posts", tags=["posts"])

@router.get("/", response_model=list[PostResponse])
async def list_posts(
    skip: int = 0,
    limit: int = 20,
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(
        select(Post).where(Post.status == "published").offset(skip).limit(limit)
    )
    return result.scalars().all()

@router.get("/{post_id}", response_model=PostResponse)
async def get_post(post_id: int, db: AsyncSession = Depends(get_db)):
    post = await db.get(Post, post_id)
    if not post:
        raise HTTPException(status_code=404, detail="Post tidak ditemukan")
    return post

@router.post("/", response_model=PostResponse, status_code=201)
async def create_post(data: PostCreate, db: AsyncSession = Depends(get_db)):
    post = Post(**data.model_dump())
    db.add(post)
    await db.flush()
    await db.refresh(post)
    return post

Autentikasi JWT

pip install python-jose[cryptography] passlib[bcrypt]
# auth.py
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from jose import JWTError, jwt

SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"

security = HTTPBearer()

async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    db: AsyncSession = Depends(get_db),
) -> User:
    try:
        payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
        user_id = payload.get("sub")
        if user_id is None:
            raise HTTPException(status_code=401, detail="Token tidak valid")
    except JWTError:
        raise HTTPException(status_code=401, detail="Token tidak valid")

    user = await db.get(User, int(user_id))
    if not user:
        raise HTTPException(status_code=401, detail="User tidak ditemukan")
    return user

# Gunakan di route
@router.post("/", response_model=PostResponse)
async def create_post(
    data: PostCreate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    # current_user sudah terautentikasi
    post = Post(**data.model_dump(), author_id=current_user.id)
    ...

Containerize dengan Docker

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

FastAPI cocok sekali sebagai microservice yang di-consume aplikasi Laravel — misalnya untuk layanan ML inference, image processing, atau data analytics yang lebih praktis dikerjakan di Python. Komunikasi antar service bisa via HTTP biasa atau message queue seperti RabbitMQ/Redis.