Salin dan Bagikan
Cara Membuat API dengan FastAPI Python
FastAPI adalah framework Python modern untuk membuat API dengan performa tinggi. Mari pelajari dari dasar.
Apa itu FastAPI?
Keunggulan FastAPI
- Sangat cepat (setara Node.js/Go)
- Auto-generate API documentation
- Type hints dan validation
- Async support
- Easy to learn
- Production ready
Setup Project
Install FastAPI
# Buat virtual environment
python -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windows
# Install FastAPI dan Uvicorn
pip install fastapi uvicorn[standard]
# Optional dependencies
pip install python-multipart # form data
pip install python-jose[cryptography] # JWT
pip install passlib[bcrypt] # password hashing
pip install sqlalchemy # database ORM
Project Structure
project/
├── app/
│ ├── __init__.py
│ ├── main.py
│ ├── config.py
│ ├── models/
│ │ └── __init__.py
│ ├── schemas/
│ │ └── __init__.py
│ ├── routers/
│ │ └── __init__.py
│ └── database.py
├── requirements.txt
└── .env
Basic API
Hello World
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
Run Server
# Development
uvicorn main:app --reload
# Production
uvicorn main:app --host 0.0.0.0 --port 8000
# Access:
# http://localhost:8000
# http://localhost:8000/docs (Swagger UI)
# http://localhost:8000/redoc (ReDoc)
Path Parameters
Basic Path Parameters
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id}
@app.get("/files/{file_path:path}")
def get_file(file_path: str):
return {"file_path": file_path}
Enum Path Parameters
from enum import Enum
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
@app.get("/models/{model_name}")
def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
return {"model_name": model_name}
Query Parameters
Basic Query Parameters
@app.get("/items/")
def read_items(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}
# Optional parameters
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
if q:
return {"item_id": item_id, "q": q}
return {"item_id": item_id}
Required Query Parameters
@app.get("/search/")
def search(q: str): # Required
return {"query": q}
Request Body
Pydantic Models
from pydantic import BaseModel, EmailStr
from typing import Optional
class UserCreate(BaseModel):
name: str
email: EmailStr
password: str
age: Optional[int] = None
class UserResponse(BaseModel):
id: int
name: str
email: EmailStr
class Config:
from_attributes = True
@app.post("/users/", response_model=UserResponse)
def create_user(user: UserCreate):
# Save to database...
return {"id": 1, "name": user.name, "email": user.email}
Validation
from pydantic import BaseModel, Field, validator
class Item(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
price: float = Field(..., gt=0)
quantity: int = Field(default=1, ge=0, le=1000)
description: str | None = Field(default=None, max_length=500)
@validator('name')
def name_must_be_valid(cls, v):
if not v.strip():
raise ValueError('Name cannot be empty')
return v.strip()
@app.post("/items/")
def create_item(item: Item):
return item
Response Models
Multiple Response Models
from typing import List
class ItemBase(BaseModel):
name: str
price: float
class ItemCreate(ItemBase):
pass
class ItemResponse(ItemBase):
id: int
class Config:
from_attributes = True
@app.get("/items/", response_model=List[ItemResponse])
def get_items():
return [
{"id": 1, "name": "Item 1", "price": 100},
{"id": 2, "name": "Item 2", "price": 200}
]
Status Codes
from fastapi import status
@app.post("/items/", status_code=status.HTTP_201_CREATED)
def create_item(item: Item):
return item
@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_item(item_id: int):
return None
Routers
Organize Routes
# routers/users.py
from fastapi import APIRouter
router = APIRouter(
prefix="/users",
tags=["users"]
)
@router.get("/")
def get_users():
return [{"id": 1, "name": "Budi"}]
@router.get("/{user_id}")
def get_user(user_id: int):
return {"id": user_id, "name": "Budi"}
# main.py
from fastapi import FastAPI
from routers import users
app = FastAPI()
app.include_router(users.router)
Database Integration
SQLAlchemy Setup
# database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./app.db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
Models
# models/user.py
from sqlalchemy import Column, Integer, String
from database import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
CRUD Operations
from fastapi import Depends
from sqlalchemy.orm import Session
from database import get_db
from models.user import User
@app.get("/users/")
def get_users(db: Session = Depends(get_db)):
users = db.query(User).all()
return users
@app.post("/users/")
def create_user(user: UserCreate, db: Session = Depends(get_db)):
db_user = User(
name=user.name,
email=user.email,
hashed_password=hash_password(user.password)
)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
Authentication
JWT Authentication
from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password):
return pwd_context.hash(password)
Protect Routes
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise HTTPException(status_code=401, detail="Invalid token")
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
user = get_user(username)
if user is None:
raise HTTPException(status_code=401, detail="User not found")
return user
@app.get("/protected/")
async def protected_route(current_user: User = Depends(get_current_user)):
return {"message": f"Hello {current_user.name}"}
Error Handling
HTTPException
from fastapi import HTTPException
@app.get("/items/{item_id}")
def get_item(item_id: int):
if item_id not in items:
raise HTTPException(
status_code=404,
detail="Item not found",
headers={"X-Error": "Item does not exist"}
)
return items[item_id]
Custom Exception Handler
from fastapi import Request
from fastapi.responses import JSONResponse
class CustomException(Exception):
def __init__(self, name: str):
self.name = name
@app.exception_handler(CustomException)
async def custom_exception_handler(request: Request, exc: CustomException):
return JSONResponse(
status_code=418,
content={"message": f"Oops! {exc.name} did something wrong."}
)
Middleware
Custom Middleware
from fastapi.middleware.cors import CORSMiddleware
import time
# CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Custom middleware
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
Deployment
Production Settings
# config.py
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
app_name: str = "My API"
debug: bool = False
database_url: str
secret_key: str
class Config:
env_file = ".env"
settings = Settings()
Docker
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Kesimpulan
FastAPI adalah framework modern yang ideal untuk building APIs. Auto-documentation dan type validation membuat development lebih cepat dan aman.
Artikel Terkait
Link Postingan : https://www.tirinfo.com/cara-membuat-api-fastapi-python/
Editor : Hendra WIjaya
Publisher :
Tirinfo
Read : 4 minutes.
Update : 7 January 2026