Membangun operasi CRUD (Create, Read, Update, Delete) dengan FastAPI memerlukan pendekatan yang efisien dan terstruktur untuk memastikan performa dan kemudahan pengelolaan. Dalam artikel ini, kita akan membahas best practice seperti penggunaan Dependency Injection, validasi data dengan Pydantic, dan pengorganisasian kode untuk menciptakan aplikasi yang scalable dan maintainable.
Best Practice
A. Gunakan Dependency Injection
Dependency Injection (DI) di FastAPI adalah mekanisme untuk menyediakan dan mengelola dependensi (komponen eksternal atau fungsi) yang dibutuhkan oleh suatu fungsi atau endpoint secara otomatis. Dengan DI, Anda dapat memisahkan logika aplikasi dari pengelolaan sumber daya atau komponen tertentu, seperti database, layanan eksternal, atau konfigurasi aplikasi, sehingga kode menjadi lebih modular, bersih, dan mudah diuji.
Bagaimana Dependency Injection Bekerja di FastAPI
FastAPI memungkinkan Anda mendefinisikan dependensi menggunakan fungsi Python biasa atau class, kemudian mendaftarkannya sebagai argumen di endpoint. FastAPI secara otomatis akan memanggil fungsi tersebut, mengelola siklus hidupnya, dan menginjeksi hasilnya ke endpoint.
Berikut adalah beberapa contoh penggunaan Dependency Injection (DI) di FastAPI:
1. Mengelola Konfigurasi Aplikasi
Gunakan DI untuk menyediakan konfigurasi global ke endpoint.
from fastapi import Depends, FastAPI
app = FastAPI()
# Fungsi dependensi
def get_config():
return {"app_name": "My FastAPI App", "version": "1.0.0"}
# Endpoint menggunakan dependensi
@app.get("/")
def read_root(config: dict = Depends(get_config)):
return {"message": f"Welcome to {config['app_name']}!"}
2. Mengelola Koneksi Database
Gunakan DI untuk menyambungkan ke database, mengelola koneksi, dan memastikan koneksi ditutup setelah selesai.
from fastapi import Depends, FastAPI
from sqlalchemy.orm import Session
from database import SessionLocal
app = FastAPI()
# Fungsi dependensi
def get_db():
db = SessionLocal() # Membuka koneksi database
try:
yield db # Mengembalikan instance database
finally:
db.close() # Menutup koneksi database
# Endpoint menggunakan koneksi database
@app.get("/users/")
def read_users(db: Session = Depends(get_db)):
users = db.query(User).all() # Query data pengguna
return users
3. Autentikasi API Key
Gunakan DI untuk memvalidasi API key yang dikirimkan oleh klien.
def get_api_key():
return "my-secret-key"
def get_service(api_key: str = Depends(get_api_key)):
return f"Service initialized with API key: {api_key}"
@app.get("/service/")
def read_service(service: str = Depends(get_service)):
return {"service": service}
4. Dependensi Bersarang
Dependensi dapat saling memanggil untuk menyusun logika yang kompleks.
def get_api_key():
return "my-secret-key"
def get_service(api_key: str = Depends(get_api_key)):
return f"Service initialized with API key: {api_key}"
@app.get("/service/")
def read_service(service: str = Depends(get_service)):
return {"service": service}
5. Logging atau Middleware Khusus
Gunakan DI untuk menyediakan logger atau middleware lainnya ke endpoint.
from fastapi import Depends, FastAPI
app = FastAPI()
# Fungsi dependensi untuk logger
def get_logger():
return {"log_level": "info", "service": "FastAPI App"}
@app.get("/log/")
def read_log(logger: dict = Depends(get_logger)):
return {"message": f"Logger is set to {logger['log_level']}"}
6. Pengelolaan Token JWT
Gunakan DI untuk memvalidasi dan memparsing token JWT.
from fastapi import Depends, FastAPI, HTTPException
import jwt
app = FastAPI()
# Fungsi untuk memvalidasi token
def get_current_user(token: str):
try:
payload = jwt.decode(token, "my-secret-key", algorithms=["HS256"])
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail="Token expired")
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token")
@app.get("/profile/")
def read_profile(user: dict = Depends(get_current_user)):
return {"user": user}
B. Definisikan Pydantic Models dengan Validasi
Pydantic adalah sebuah library Python yang digunakan untuk memvalidasi data dan mendefinisikan skema data menggunakan tipe data Python. Library ini mempermudah validasi dan konversi data secara otomatis berdasarkan anotasi tipe, sehingga cocok untuk digunakan dalam pengembangan aplikasi berbasis data atau API.
Mengapa Pydantic ?
- Validasi Data Otomatis:
- Input dari klien (seperti JSON) divalidasi secara otomatis berdasarkan skema yang didefinisikan dengan Pydantic.
- FastAPI memanfaatkan kemampuan Pydantic untuk memastikan data yang diterima valid sebelum diproses.
- Definisi Skema yang Jelas:
- Skema data didefinisikan menggunakan class Python berbasis
BaseModeldari Pydantic. - Skema ini juga digunakan untuk mendokumentasikan API secara otomatis menggunakan OpenAPI (Swagger).
- Skema data didefinisikan menggunakan class Python berbasis
- Konversi Data Otomatis:
- Pydantic secara otomatis mengonversi tipe data saat diperlukan (misalnya, string menjadi integer).
- Hal ini mengurangi kode boilerplate untuk parsing dan validasi data.
- Reusabilitas dan Konsistensi:
- Model Pydantic dapat digunakan kembali di berbagai endpoint atau komponen aplikasi.
- Membantu menjaga konsistensi data di seluruh aplikasi.
- Error Handling yang Terintegrasi:
- Pydantic menghasilkan error yang terstruktur saat data tidak valid, dan FastAPI menggunakan error ini untuk memberikan respons HTTP 422 dengan detail kesalahan yang lengkap.
- Kompatibilitas dengan OpenAPI dan Swagger:
- Skema Pydantic secara otomatis diintegrasikan dengan dokumentasi API yang dihasilkan oleh FastAPI.
- Hal ini membantu pengembang dan pengguna API memahami input/output yang diperlukan.
1. Validasi Input
Gunakan model Pydantic untuk mendefinisikan struktur data yang harus diterima oleh endpoint.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
id: int
name: str
email: str
@app.post("/users/")
def create_user(user: User):
return {"message": f"User {user.name} has been created!"}
- Input JSON akan divalidasi berdasarkan model
User. - Jika data tidak sesuai (contoh:
idadalah string), FastAPI akan otomatis memberikan error respons.
2. Output Model
Gunakan model Pydantic untuk menentukan struktur data yang dikembalikan oleh endpoint.
class UserResponse(BaseModel):
id: int
name: str
@app.get("/users/{user_id}", response_model=UserResponse)
def get_user(user_id: int):
return {"id": user_id, "name": "John Doe", "extra_field": "ignored"}- Field tambahan seperti
extra_fieldakan diabaikan karena tidak sesuai dengan modelUserResponse.
3. Validasi Kustom
Tambahkan validasi khusus menggunakan decorator @validator di Pydantic.
from pydantic import BaseModel, validator
class User(BaseModel):
name: str
age: int
@validator("age")
def validate_age(cls, value):
if value < 0:
raise ValueError("Age must be a positive number")
return value
@app.post("/validate-user/")
def validate_user(user: User):
return {"message": f"User {user.name} is valid."}
B. Menangani Error dan Exception
FastAPI memungkinkan Anda untuk menangani error dan exception secara eksplisit. Ini membantu untuk memberikan umpan balik yang jelas kepada pengguna ketika terjadi kesalahan.
from fastapi import HTTPException
@app.get("/items/{item_id}")
def get_item(item_id: int):
item = get_item_from_db(item_id)
if not item:
raise HTTPException(status_code=404, detail="Item not found")
return itemC. Gunakan BackgroundTasks untuk Proses Asinkron
Untuk pekerjaan yang memerlukan waktu lama (misalnya pengiriman email atau pemrosesan data yang berat), gunakan BackgroundTasks. Ini memungkinkan Anda untuk menangani tugas-tugas tersebut di background tanpa membuat pengguna menunggu.
from fastapi import BackgroundTasks
def send_email(email: str):
# Kode untuk mengirim email
pass
@app.post("/send-notification/")
def send_notification(background_tasks: BackgroundTasks, email: str):
background_tasks.add_task(send_email, email)
return {"message": "Notification sent in the background"}D. Gunakan Middlewares untuk Pengelolaan Global
Middlewares dapat digunakan untuk menangani proses yang berlaku untuk setiap request, seperti logging, CORS, autentikasi, atau pengolahan header.
from fastapi import FastAPI
app = FastAPI()
@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 responseE. Membuat Dokumentasi API
FastAPI secara otomatis menghasilkan dokumentasi API yang sangat berguna menggunakan OpenAPI dan Swagger UI. Anda tidak perlu menulis dokumentasi manual, karena FastAPI melakukan ini untuk Anda. Gunakan endpoint /docs untuk melihat antarmuka Swagger yang interaktif.
@app.get("/items/")
def get_items():
"""
Retrieve a list of items.
Returns:
List of items
"""
return itemsF. Penerapan CORS (Cross-Origin Resource Sharing)
Jika aplikasi Anda perlu diakses dari domain yang berbeda (misalnya front-end dan back-end terpisah), pastikan untuk mengonfigurasi CORS dengan benar.
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Atau domain yang lebih spesifik
allow_credentials=True,
allow_methods=["*"], # Atau pilih metode HTTP yang dibolehkan
allow_headers=["*"],
)G. Gunakan Asynchronous Programming untuk Kecepatan
FastAPI mendukung pemrograman asinkron (asyncio). Gunakan async dan await untuk operasi I/O yang lama (seperti pemanggilan API eksternal atau akses database) agar aplikasi Anda lebih responsif dan efisien.
@app.get("/items/{item_id}")
async def get_item(item_id: int):
item = await get_item_from_db(item_id) # Menggunakan operasi async
return itemH. Pengujian dan Unit Testing
Pengujian adalah bagian penting dari setiap aplikasi. FastAPI terintegrasi dengan baik dengan framework pengujian seperti pytest. Anda bisa menulis pengujian untuk endpoint API dan logika bisnis aplikasi dengan mudah.
from fastapi.testclient import TestClient
client = TestClient(app)
def test_get_item():
response = client.get("/items/1")
assert response.status_code == 200
assert response.json() == {"name": "Item 1", "price": 10.0}I. Optimalisasi dan Keamanan
Beberapa aspek yang perlu diperhatikan untuk meningkatkan kinerja dan keamanan aplikasi FastAPI:
- Gunakan HTTPS untuk enkripsi komunikasi.
- Rate Limiting untuk membatasi jumlah request dari pengguna.
- Autentikasi dan Otorisasi dengan OAuth2, JWT (JSON Web Tokens), atau Basic Auth.
- Logging untuk memantau kinerja dan aktivitas API.
- Validation untuk memastikan bahwa input yang diterima API valid dan aman.
J. Menyusun Kode dengan Struktur yang Bersih
Meskipun FastAPI memungkinkan Anda untuk menulis kode yang sangat sederhana, untuk aplikasi yang lebih besar, pastikan Anda mengikuti prinsip-prinsip desain perangkat lunak yang baik. Pisahkan aplikasi Anda ke dalam folder yang terstruktur dengan baik, misalnya:
/app/models/untuk model Pydantic atau ORM./app/routers/untuk definisi route./app/services/untuk logika bisnis./app/utils/untuk fungsi-fungsi utilitas.
Struktur Direktori
Berikut adalah struktur proyek FastAPI yang disarankan, terutama untuk aplikasi yang lebih besar atau yang memerlukan pengelolaan kode yang lebih baik. Struktur ini memisahkan kode berdasarkan fungsionalitas, sehingga lebih mudah untuk memelihara, mengembangkan, dan menguji aplikasi.
Struktur Direktori yang Direkomendasikan
/app
├── /api # Folder untuk router/endpoints
│ ├── /v1 # Versi API (misalnya v1, v2, dst.)
│ │ ├── __init__.py
│ │ ├── endpoints.py # Tempat definisi route
│ │ └── users.py # Route terkait "users"
│ └── __init__.py
├── /core # Kode utama dan konfigurasi aplikasi
│ ├── __init__.py
│ ├── config.py # Konfigurasi aplikasi (misalnya, database, JWT)
│ ├── security.py # Fungsi terkait autentikasi dan keamanan
│ ├── exceptions.py # Kode penanganan error umum
│ └── utils.py # Fungsi utilitas umum
├── /db # Kode terkait database (ORM, koneksi, dsb.)
│ ├── __init__.py
│ ├── base.py # Kelas dasar untuk model ORM
│ ├── models.py # Definisi model database
│ ├── session.py # Fungsi terkait sesi database
│ └── crud.py # Operasi CRUD (Create, Read, Update, Delete)
├── /models # Pydantic models untuk validasi
│ ├── __init__.py
│ ├── user.py # Model Pydantic untuk User
│ └── item.py # Model Pydantic untuk Item
├── /services # Logika bisnis dan komunikasi antar komponen
│ ├── __init__.py
│ ├── user_service.py # Layanan yang berhubungan dengan pengguna
│ └── item_service.py # Layanan yang berhubungan dengan item
├── /tests # Folder untuk pengujian aplikasi
│ ├── __init__.py
│ ├── test_users.py # Pengujian untuk endpoint user
│ └── test_items.py # Pengujian untuk endpoint item
├── /scripts # Skrip untuk setup dan maintenance (misalnya migration, seed data)
└── main.py # Titik masuk aplikasi FastAPIDeskripsi Folder dan File
/api
Folder ini berisi kode untuk router dan endpoint API. Anda bisa memisahkan route berdasarkan versi API atau fitur (misalnya, user, item, order). Setiap modul atau file bisa berisi route yang terkait dengan entitas tertentu, dan diimpor ke dalam file utama aplikasi.
- /v1/endpoints.py: Menyimpan definisi route seperti
GET,POST,PUT, atauDELETEuntuk operasi terkait entitas tertentu.
/core
Folder ini berisi konfigurasi dan logika umum yang digunakan oleh seluruh aplikasi.
- config.py: Tempat menyimpan pengaturan konfigurasi aplikasi seperti koneksi database, pengaturan JWT, dsb.
- security.py: Berisi kode terkait autentikasi, otorisasi, dan validasi token (misalnya menggunakan OAuth2 atau JWT).
- exceptions.py: Berisi kode untuk menangani pengecualian atau kesalahan yang mungkin muncul di aplikasi.
- utils.py: Menyimpan fungsi-fungsi utilitas yang berguna secara umum dalam aplikasi.
/db
Berisi kode untuk pengelolaan database dan ORM (Object-Relational Mapping) jika Anda menggunakan database. Biasanya di sini Anda akan mendefinisikan model database dan CRUD operations.
- models.py: Menyimpan model ORM untuk entitas seperti
User,Item, dsb. - session.py: Kode untuk menangani sesi koneksi ke database.
- crud.py: Menyimpan logika CRUD, misalnya menambahkan data, mendapatkan data, memperbarui, dan menghapus data.
/models
Berisi Pydantic models yang digunakan untuk validasi input/output API. Ini adalah tempat untuk mendefinisikan struktur data yang diterima dan dikirim oleh API.
- user.py: Model Pydantic untuk validasi data pengguna.
- item.py: Model Pydantic untuk validasi data item.
/services
Menampung logika bisnis yang lebih kompleks dan komunikasi antara model, database, dan API. Di sini Anda bisa mendefinisikan fungsi atau layanan yang menangani operasi lebih mendalam atau yang menghubungkan beberapa entitas.
- user_service.py: Menyediakan fungsi terkait pengelolaan pengguna, seperti registrasi, login, atau perubahan data.
- item_service.py: Menyediakan logika terkait pengelolaan item (misalnya menambah, mengedit, atau menghapus item).
/tests
Folder ini menyimpan unit tests dan integration tests untuk aplikasi Anda. Anda bisa menggunakan framework seperti pytest untuk menulis pengujian yang memastikan API Anda berfungsi dengan benar.
- test_users.py: Pengujian untuk memastikan endpoint dan fungsionalitas terkait pengguna berjalan sesuai yang diharapkan.
- test_items.py: Pengujian untuk memastikan endpoint dan fungsionalitas terkait item berjalan sesuai yang diharapkan.
/scripts
Tempat untuk skrip tambahan seperti migration database, seed data, atau penanganan tugas administratif lainnya.
main.py
Ini adalah titik masuk utama untuk aplikasi FastAPI Anda. Di sini, Anda akan mengimpor dan menyatukan router dari /api, konfigurasi dari /core, dan middleware atau pengaturan tambahan lainnya.
Kelebihan Struktur Ini
- Modular: Aplikasi dipisahkan berdasarkan fungsionalitasnya (misalnya, API, database, service), sehingga lebih mudah dipelihara.
- Skalabilitas: Dengan pembagian seperti ini, Anda dapat dengan mudah menambah fitur atau versi API baru tanpa mengganggu kode yang sudah ada.
- Pengujian: Folder
testsmembantu Anda untuk menguji aplikasi dan memastikan bahwa kode yang baru ditambahkan tidak merusak fungsionalitas yang ada. - Kebersihan Kode: Memisahkan logika bisnis dan pengelolaan database ke dalam folder terpisah menjaga kode tetap bersih dan terorganisir.
struktur direktori multiple apps
/my_project
├── /app
│ ├── /app1 # Aplikasi pertama
│ │ ├── /api # API routers untuk app1
│ │ │ ├── __init__.py
│ │ │ ├── products.py
│ │ │ └── orders.py
│ │ ├── /models # Models untuk app1
│ │ │ ├── __init__.py
│ │ │ ├── product.py
│ │ │ └── order.py
│ │ ├── /services # Service layer untuk app1
│ │ │ ├── __init__.py
│ │ │ ├── product_service.py
│ │ │ └── order_service.py
│ │ ├── main.py # Titik masuk untuk app1
│ │ └── config.py # Konfigurasi khusus app1
│ ├── /app2 # Aplikasi kedua
│ │ ├── /api # API routers untuk app2
│ │ │ ├── __init__.py
│ │ │ ├── users.py
│ │ │ └── payments.py
│ │ ├── /models # Models untuk app2
│ │ │ ├── __init__.py
│ │ │ ├── user.py
│ │ │ └── payment.py
│ │ ├── /services # Service layer untuk app2
│ │ │ ├── __init__.py
│ │ │ ├── user_service.py
│ │ │ └── payment_service.py
│ │ ├── main.py # Titik masuk untuk app2
│ │ └── config.py # Konfigurasi khusus app2
├── /core # Kode inti yang digunakan bersama
│ ├── __init__.py
│ ├── config.py # Konfigurasi bersama (misalnya database, JWT)
│ ├── exceptions.py # Exception handler global
│ ├── security.py # Fungsi keamanan dan autentikasi umum
│ └── utils.py # Utilitas umum yang digunakan di seluruh aplikasi
├── /db # Koneksi database dan model umum
│ ├── __init__.py
│ ├── models.py # Model database umum, jika ada (misalnya User)
│ ├── session.py # Fungsi untuk mengelola session database
│ ├── crud.py # Operasi CRUD umum
│ └── base.py # Kelas base untuk model ORM
├── /tests # Folder pengujian
│ ├── __init__.py
│ ├── test_app1.py # Pengujian untuk app1
│ ├── test_app2.py # Pengujian untuk app2
├── requirements.txt # Dependensi Python (untuk kedua aplikasi)
├── Dockerfile # Docker configuration (jika digunakan)
├── README.md # Deskripsi proyek
└── main.py # Titik masuk utama (untuk menjalankan aplikasi)
4. Contoh Struktur Proyek Lebih Kompleks
Untuk proyek lebih besar, Anda bisa menambahkan folder lain seperti /docs untuk dokumentasi, /notifications untuk layanan terkait email/notifications, atau /background_tasks untuk task yang berjalan di background.
Study Case
Database & Languange Programming
- postgresql min v14
- python min v3.10
app structure
/project_root
├── /ecommerce
│ └── /app
│ ├── /api
│ │ └── /v1
│ │ ├── products.py
│ │ └── .........py
│ ├── /core
│ │ └── config.py
│ ├── /db
│ │ ├── base.py
│ │ ├── models.py
│ │ ├── session.py
│ │ └── crud.py
│ ├── /models
│ │ ├── product.py
│ │ └── ........py
│ ├── /services
│ │ ├── product_service.py
│ │ └── ......._service.py
│ └── main.py
├── /.venv
└── requirements.txt
- jika ada endpoint tambahan selain product tinggal buat file endpoint, models, dan servicenya saja
requirements.txt
fastapi==0.115.6
psycopg2-binary==2.9.10
pydantic==2.10.4
pydantic_core==2.27.2
SQLAlchemy==2.0.36
uvicorn==0.34.0app.api.v1
- .products.py
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from app.models.product import ProductCreate, Product
from app.services.product_services import (
create_product_service,
get_all_products_service,
get_single_product_service,
update_product_service,
delete_product_service
)
from app.db.session import get_db
router = APIRouter()
@router.post("/", response_model=Product)
def add_product(product: ProductCreate, db: Session = Depends(get_db)):
return create_product_service(db, product)
@router.get("/", response_model=list[Product])
def list_products(db: Session = Depends(get_db)):
return get_all_products_service(db)
@router.get("/{product_id}", response_model=Product)
def get_product(product_id: int, db: Session = Depends(get_db)):
product = get_single_product_service(db, product_id)
if not product:
raise HTTPException(status_code=404, detail="Product not found")
return product
@router.put("/{product_id}", response_model=Product)
def update_product(product_id: int, product: ProductCreate, db: Session = Depends(get_db)):
update_product = update_product_service(db, product_id, product)
if not update_product:
raise HTTPException(status_code=404, detail="Product not found")
return update_product
@router.delete("/{product_id}", response_model=Product)
def delete_product(product_id: int, db: Session = Depends(get_db)):
delete_product = delete_product_service(db, product_id)
if not delete_product:
raise HTTPException(status_code=404, detail="Product not found")
return delete_productKode tersebut adalah implementasi CRUD (Create, Read, Update, Delete) untuk mengelola data produk menggunakan FastAPI, dengan praktik terbaik seperti pemisahan logika layanan (service) dan penggunaan Dependency Injection. Berikut penjelasan singkatnya:
- Import Library dan Modul:
- Mengimpor modul seperti
APIRouteruntuk membuat grup endpoint,Dependsuntuk Dependency Injection, danHTTPExceptionuntuk menangani error. - Mengimpor model data (
ProductCreate,Product) dan layanan (product_services) yang berisi logika CRUD. - Mengimpor
get_dbuntuk Dependency Injection koneksi database.
- Mengimpor modul seperti
- Router Setup:
router = APIRouter(): Membuat router untuk grup endpoint yang dapat dipisahkan dari file utama.
- Endpoint CRUD:
@router.post("/"): Endpoint untuk menambahkan produk baru dengan validasi data dari modelProductCreatedan menyimpan ke database menggunakan layanancreate_product_service.@router.get("/"): Endpoint untuk mendapatkan daftar semua produk menggunakan layananget_all_products_service.@router.get("/{product_id}"): Endpoint untuk mengambil detail produk berdasarkanproduct_id, dengan validasi keberadaan produk. Jika tidak ditemukan, akan mengembalikan error 404.@router.put("/{product_id}"): Endpoint untuk memperbarui data produk berdasarkanproduct_iddengan data baru yang divalidasi melaluiProductCreate.@router.delete("/{product_id}"): Endpoint untuk menghapus produk berdasarkanproduct_id. Jika produk tidak ditemukan, mengembalikan error 404.
- Dependency Injection:
db: Session = Depends(get_db): Setiap endpoint menggunakan koneksi database yang dikelola secara otomatis denganget_db.
- Response Model:
response_model: Mengontrol struktur data output menggunakan model Pydantic (Productataulist[Product]).
app.core.config.py
DATABASE_URL = "postgresql://root:admin1@localhost/ecommerce"Kode tersebut adalah string koneksi database untuk PostgreSQL. Artinya, aplikasi akan terhubung ke database PostgreSQL dengan:
- Username:
root - Password:
admin1 - Host:
localhost(komputer lokal) - Database:
ecommerce.
app.core.db
- .base.py
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()digunakan dalam SQLAlchemy untuk membuat kelas dasar yang menjadi dasar semua model tabel database Anda.
Penjelasan:
declarative_base:- Fungsi yang menghasilkan kelas dasar yang disebut
Base. - Kelas ini digunakan untuk mendefinisikan model tabel di database (ORM – Object Relational Mapping).
- Fungsi yang menghasilkan kelas dasar yang disebut
Base:- Semua model tabel database akan mewarisi
Base. - Ini memungkinkan SQLAlchemy mengenali model Anda sebagai tabel database.
- Semua model tabel database akan mewarisi
- .crud.py
from sqlalchemy.orm import Session
from app.db.models import Product
from app.models.product import ProductCreate
# Fungsi untuk menambahkan produk baru
def create_product(db: Session, product: ProductCreate):
db_product = Product(
name=product.name,
description=product.description,
price=product.price,
stock=product.stock,
)
db.add(db_product)
db.commit()
db.refresh(db_product)
return db_product
# Fungsi untuk mendapatkan daftar semua produk
def get_products(db: Session):
return db.query(Product).all()
# Fungsi untuk mendapatkan produk berdasarkan ID
def get_product_by_id(db: Session, product_id: int):
return db.query(Product).filter(Product.id == product_id).first()
# Fungsi untuk mengupdate produk berdasarkan ID
def update_product(db: Session, product_id: int, product_data: ProductCreate):
db_product = db.query(Product).filter(Product.id == product_id).first()
if db_product:
db_product.name = product_data.name
db_product.description = product_data.description
db_product.price = product_data.price
db_product.stock = product_data.stock
db.commit()
db.refresh(db_product)
return db_product
return None
# Fungsi untuk menghapus produk berdasarkan ID
def delete_product(db: Session, product_id: int):
db_product = db.query(Product).filter(Product.id == product_id).first()
if db_product:
db.delete(db_product)
db.commit()
return db_product
return NoneKode tersebut adalah implementasi fungsi-fungsi CRUD (Create, Read, Update, Delete) untuk mengelola data produk menggunakan SQLAlchemy. Berikut penjelasannya:
- Import:
Session: Objek sesi database untuk menjalankan query.Product: Model tabel database untuk produk.ProductCreate: Skema Pydantic untuk validasi input data produk.
- Fungsi CRUD:
create_product: Menambahkan produk baru ke database dengan data dariProductCreate.get_products: Mengambil semua produk dari tabelProduct.get_product_by_id: Mengambil produk tertentu berdasarkanproduct_id.update_product: Memperbarui data produk berdasarkanproduct_iddan data baru dariProductCreate.delete_product: Menghapus produk dari database berdasarkanproduct_id.
- Operasi SQLAlchemy:
db.add(): Menambahkan data baru ke sesi database.db.commit(): Menyimpan perubahan ke database.db.refresh(): Memperbarui objek setelah disimpan ke database.db.query().filter().first(): Melakukan pencarian berdasarkan kondisi.db.delete(): Menghapus data dari database.
- .models.py
from sqlalchemy import Column, Integer, String, Float
from app.db.base import Base
class Product(Base):
__tablename__ = "products"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
description = Column(String)
price = Column(Float)
stock = Column(Integer)Fungsi dari kode tersebut adalah untuk mengelola koneksi database dalam aplikasi. Secara spesifik:
- Membuat Engine:
create_enginedigunakan untuk menghubungkan aplikasi ke database berdasarkanDATABASE_URL.
- Membuat Sesi Database:
SessionLocaladalah kelas sesi untuk menjalankan query database secara terisolasi.
- Dependency Injection (
get_db):- Fungsi
get_dbmenyediakan sesi database ke endpoint FastAPI dan memastikan sesi ditutup setelah selesai, sehingga menghindari kebocoran koneksi.
- Fungsi
- .session.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from app.core.config import DATABASE_URL
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(
autocommit=False,
autoflush=False,
bind=engine
)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()Kode tersebut mengatur koneksi database menggunakan SQLAlchemy untuk aplikasi. Berikut penjelasannya:
Penjelasan Komponen Kode:
create_engine:- Membuat engine koneksi ke database berdasarkan URL koneksi yang didefinisikan di
DATABASE_URL. DATABASE_URLadalah string koneksi database (misalnya, PostgreSQL atau SQLite).
- Membuat engine koneksi ke database berdasarkan URL koneksi yang didefinisikan di
sessionmaker:- Digunakan untuk membuat SessionLocal, yaitu kelas sesi database yang digunakan untuk menjalankan operasi query.
- Parameter:
autocommit=False: Menonaktifkan commit otomatis; semua perubahan harus disimpan secara manual dengandb.commit().autoflush=False: Menonaktifkan flush otomatis; SQLAlchemy tidak akan mengirimkan perubahan ke database hinggadb.commit()dipanggil.bind=engine: Menghubungkan sesi dengan engine yang telah dibuat.
get_db:- Fungsi Dependency Injection untuk mengelola sesi database.
- Membuka sesi database (
db = SessionLocal()), menyediakan sesi ini ke fungsi yang memerlukan (yield db), lalu memastikan sesi ditutup setelah selesai (db.close()).
Fungsi Kode:
- Membuat Engine: Menginisialisasi koneksi ke database.
- Membuat Sesi:
SessionLocalmemungkinkan operasi database dilakukan dalam sesi terisolasi. - Dependency Injection:
get_dbmenyediakan sesi database untuk digunakan di endpoint FastAPI tanpa harus mengelola koneksi secara manual.
app.models
- product.py
from pydantic import BaseModel
class ProductBase(BaseModel):
name : str
description : str
price : float
stock : int
class ProductCreate(ProductBase):
pass
class Product(ProductBase):
id : int
class Config:
orm_mode = True
Kode tersebut mendefinisikan model Pydantic untuk validasi data produk:
ProductBase: Model dasar dengan atributname,description,price, danstock.ProductCreate: Digunakan untuk validasi input saat membuat produk baru, mewarisi dariProductBase.Product: Menambahkan atributiduntuk output data, denganorm_mode = Trueagar kompatibel dengan model ORM seperti SQLAlchemy.
app.services
- product_services.ps
from sqlalchemy.orm import Session
from app.db.crud import (
create_product, get_products, get_product_by_id, update_product, delete_product
)
from app.models.product import ProductCreate
def create_product_service(db: Session, product: ProductCreate):
return create_product(db, product)
def get_all_products_service(db: Session):
return get_products(db)
def get_single_product_service(db: Session, product_id: int):
return get_product_by_id(db, product_id)
def update_product_service(db: Session, product_id: int, product: ProductCreate):
return update_product(db, product_id, product)
def delete_product_service(db: Session, product_id: int):
return delete_product(db, product_id)Fungsi dari kode tersebut adalah untuk membuat layer layanan (service layer) yang bertugas sebagai perantara antara logika bisnis (CRUD) dan endpoint API.
Penjelasan Fungsi:
create_product_service:- Memanggil fungsi
create_productuntuk menambahkan produk baru ke database.
- Memanggil fungsi
get_all_products_service:- Memanggil fungsi
get_productsuntuk mengambil semua data produk dari database.
- Memanggil fungsi
get_single_product_service:- Memanggil fungsi
get_product_by_iduntuk mengambil data satu produk berdasarkanproduct_id.
- Memanggil fungsi
update_product_service:- Memanggil fungsi
update_productuntuk memperbarui data produk berdasarkanproduct_id.
- Memanggil fungsi
delete_product_service:- Memanggil fungsi
delete_productuntuk menghapus data produk berdasarkanproduct_id.
- Memanggil fungsi
Tujuan:
- Memisahkan logika bisnis (CRUD) dari endpoint API.
- Mempermudah pengelolaan, pengujian, dan pemeliharaan kode dengan struktur yang modular.
main.py
from fastapi import FastAPI
from app.api.v1.products import router as products_router
from app.db.base import Base
from app.db.session import engine
app = FastAPI()
# include routers
app.include_router(products_router, prefix="/v1/products", tags=["products"])
# initialize database
Base.metadata.create_all(bind=engine)
@app.get("/")
def read_root():
return {"message": "welcome to the product API"}
Kode tersebut digunakan untuk membuat dan menginisialisasi aplikasi API dengan FastAPI, termasuk konfigurasi rute, pengaturan database, dan endpoint dasar. Berikut fungsinya:
Penjelasan Fungsi:
FastAPI():- Membuat instance aplikasi FastAPI.
app.include_router:- Menyertakan router
products_routeruntuk menangani semua rute terkait produk. prefix="/v1/products": Menentukan prefiks URL untuk endpoint produk (misalnya,/v1/products).tags=["products"]: Menambahkan kategori dalam dokumentasi API.
- Menyertakan router
Base.metadata.create_all(bind=engine):- Menginisialisasi tabel-tabel database sesuai model yang didefinisikan di ORM SQLAlchemy.
engine: Objek koneksi database.
- Endpoint
/:- Endpoint dasar yang mengembalikan pesan selamat datang (
{"message": "welcome to the product API"}).
- Endpoint dasar yang mengembalikan pesan selamat datang (
app run
cd path/to/project_root/
# install environment
python -m venv .venv
# activate environemnt
source .venv/bin/activate
# install library
pip install -r requirements.txt
cd ecommerce
uvicorn app.main:app --reload
