Flask Api & Mysql
Kita akan membuat API untuk mengelola data Mahasiswa dan Program Studi
Kita akan menggunakan UV sebagai package manager di python pengganti pip, Flask sebagai framework, dan MySQL sebagai database.
Membangun REST API
Apa yang Akan Kita Pelajari?
Kita akan membuat API untuk mengelola data Mahasiswa dan Program Studi. Hasil akhirnya adalah endpoint URL yang bisa kamu gunakan untuk:
- Melihat daftar mahasiswa beserta prodinya.
- Menambah, mengedit, dan menghapus data mahasiswa.
- Data tersimpan permanen di database MySQL.
Prasyarat
Sebelum memulai, pastikan kamu memiliki:
- Python (versi 3.14.* ke atas disarankan).
- UV (Tools modern pengganti pip/virtualenv).
- MySQL Database (Bisa menggunakan XAMPP, Laragon, Docker, atau WSL).
Langkah 1: Setup Project dengan UV
Mengapa UV? UV jauh lebih cepat daripada pip standar dalam menginstall paket dan membuat virtual environment.
-
Buat folder baru dan masuk ke dalamnya:
bash mkdir flask-api-mysql cd flask-api-mysql -
Inisialisasi project dengan UV:
bash uv init -p 3.14.0 -
Aktifkan virutalenv :
bash .venv\Scripts\activate -
Install library yang dibutuhkan:
bash uv add flask flask-sqlalchemy pymysqlInformasi
flask: Framework.flask-sqlalchemy: ORM (Object Relational Mapper) agar kita bisa mengelola database menggunakan kode Python, bukan SQL manual.pymysql: Driver agar Python bisa "terkoneksi" dengan MySQL.
Langkah 2: Struktur Folder
Agar kode rapi, kita akan memisahkan logika database (Model) dengan logika aplikasi (Controller/Routes). Buat struktur seperti ini:
Informasi
- app.py: Entry point & Routes (Controller)
- models.py: Definisi Table Database (Model)
Langkah 3: Membuat Model Database (models/models.py)
Langkah ini mendefinisikan "schema" data kita. Kita menggunakan SQLAlchemy.
Mengapa ada BaseModel?
Perhatikan kelas BaseModel. Kita membuatnya agar setiap tabel otomatis punya kolom created_at dan updated_at tanpa perlu kita tulis ulang di setiap tabel. Ini prinsip DRY (Don't Repeat Yourself).
Buat file models/models.py:
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# 1. Base Model (Template untuk semua table)
class BaseModel(db.Model):
__abstract__ = True # Ini tidak akan dibuat jadi tabel, hanya template
created_at = db.Column(db.DateTime, nullable=False, default=datetime.now)
updated_at = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
# 2. Model Mahasiswa
class Mahasiswa(BaseModel):
__tablename__ = 'mahasiswa'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
npm = db.Column(db.String(50), nullable=False, unique=True)
profile_picture = db.Column(db.String(50), nullable=False)
# Foreign Key ke Prodi
prodi_id = db.Column(db.Integer, db.ForeignKey('prodi.id'))
# Relationship (Relasi agar bisa memanggil m.prodi)
prodi = db.relationship('Prodi', uselist=False, back_populates='mahasiswa')
# Helper untuk convert object ke JSON
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'npm': self.npm,
'profile_picture': self.profile_picture,
'prodi_id': self.prodi_id,
'created_at': self.created_at,
'updated_at': self.updated_at
}
# 3. Model Prodi
class Prodi(BaseModel):
__tablename__ = 'prodi'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
# Relasi balik ke Mahasiswa
mahasiswa = db.relationship("Mahasiswa", back_populates="prodi", lazy=True)
def to_dict(self):
return {
'id': self.id,
'name': self.name
}Langkah 4: Konfigurasi & Routes (app.py)
Sekarang kita mulai membuat API.
Warning
Sebelum menjalankan kode ini, buka MySQL client kamu (phpMyAdmin/DBeaver) dan buat database baru bernama flask-api.
Salin kode berikut ke app.py:
from flask import Flask, jsonify
# Format: mysql+pymysql://username:password@host/nama_database
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:123@localhost/flask-api"
db.init_app(app)
# Route Cek Server
@app.route("/")
def index():
return jsonify({
"meta": {
"code": 200,
"message": "Server is up"
},
"data": None
}), 200
if __name__ == "__main__":
with app.app_context():
# Membuat tabel otomatis jika belum ada
db.create_all()
app.run(debug=True)Jalankan project dengan :
python app.pyCoba akses di browser dengan url http://localhost:5000, seharusnya di browser kamu tampil seperti berikut ini
{
"meta": {
"code": 200,
"message": "Server is up"
},
"data": null
}Selanjutnya kita akan melengkapi CRUD untuk mahasiswa nya pada file app.py
from flask import Flask, jsonify, request
from models.models import db, Mahasiswa, Prodi
app = Flask(__name__)
# Konfigurasi Koneksi Database
# Format: mysql+pymysql://username:password@host/nama_database
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:123@localhost/flask-api"
db.init_app(app)
# Route Cek Server
@app.route("/")
def index():
return jsonify({
"meta": {
"code": 200,
"message": "Server is up"
},
"data": None
}), 200
# =========================================
# CRUD MAHASISWA
# =========================================
# 1. READ ALL (Mengambil semua data)
@app.route("/mahasiswa", methods=["GET"])
def mahasiswa():
list_mahasiswa = Mahasiswa.query.all()
# Kita menggabungkan data mahasiswa dengan data prodi-nya
data_json = []
for m in list_mahasiswa:
m_dict = m.to_dict()
if m.prodi:
m_dict["prodi"] = m.prodi.to_dict()
else:
m_dict["prodi"] = None
data_json.append(m_dict)
return jsonify({
"meta": {
"code": 200,
"message": "List Mahasiswa"
},
"data": data_json
}), 200
# 2. READ ONE (Detail Mahasiswa)
@app.route("/mahasiswa/<int:id>", methods=["GET"])
def detail_mahasiswa(id):
# get_or_404 otomatis return error 404 jika data tidak ada
selected_mahasiswa = Mahasiswa.query.get_or_404(id)
return jsonify({
"meta": {
"code": 200,
"message": "Detail Mahasiswa"
},
"data": selected_mahasiswa.to_dict()
}), 200
# 3. CREATE (Menambah Mahasiswa)
@app.route("/mahasiswa", methods=["POST"])
def tambah_mahasiswa():
try:
data = request.get_json()
# Validasi sederhana (Opsional tapi disarankan)
if not data.get("npm") or not data.get("name"):
return jsonify({"meta": {"code": 400, "message": "Nama dan NPM wajib diisi"}}), 400
new_mahasiswa = Mahasiswa(
name=data["name"],
npm=data["npm"],
profile_picture=data.get("profile_picture", "default.jpg"), # Kasih default jika kosong
prodi_id=data.get("prodi_id")
)
db.session.add(new_mahasiswa)
db.session.commit() # Simpan permanen ke DB
return jsonify({
"meta": {
"code": 201,
"message": "Berhasil menambahkan mahasiswa"
},
"data": new_mahasiswa.to_dict()
}), 201
except Exception as e:
# Selalu handle error agar server tidak crash
return jsonify({
"meta": {
"code": 500,
"message": f"Internal Server Error: {str(e)}"
},
"data": None
}), 500
# 4. UPDATE (Edit Mahasiswa)
@app.route("/mahasiswa/<int:id>", methods=["PUT", "PATCH"])
def update_mahasiswa(id):
try:
data = request.get_json()
selected_mahasiswa = Mahasiswa.query.get_or_404(id)
# Update field yang ada saja
if "name" in data: selected_mahasiswa.name = data["name"]
if "npm" in data: selected_mahasiswa.npm = data["npm"]
if "profile_picture" in data: selected_mahasiswa.profile_picture = data["profile_picture"]
if "prodi_id" in data: selected_mahasiswa.prodi_id = data["prodi_id"]
db.session.commit()
return jsonify({
"meta": {
"code": 200,
"message": "Berhasil update mahasiswa"
},
"data": selected_mahasiswa.to_dict()
})
except Exception as e:
return jsonify({
"meta": {
"code": 500,
"message": str(e)
}
}), 500
# 5. DELETE (Hapus Mahasiswa)
@app.route("/mahasiswa/<int:id>", methods=["DELETE"])
def delete_mahasiswa(id):
try:
selected_mahasiswa = Mahasiswa.query.get_or_404(id)
db.session.delete(selected_mahasiswa)
db.session.commit()
return jsonify({
"meta": {
"code": 200,
"message": "Berhasil menghapus mahasiswa"
},
"data": selected_mahasiswa.to_dict()
})
except Exception as e:
return jsonify({
"meta": {
"code": 500,
"message": "Internal Server Error"
}
}), 500
# Endpoint Tambahan: List Prodi
@app.route("/prodi", methods=["GET"])
def prodi():
list_prodi = Prodi.query.all()
return jsonify({
"meta": {
"code": 200,
"message": "List Prodi"
},
# Menampilkan prodi beserta list mahasiswanya (Nested)
"data": [{**p.to_dict(), "mahasiswa": [m.to_dict() for m in p.mahasiswa]} for p in list_prodi]
}), 200
if __name__ == "__main__":
with app.app_context():
# Membuat tabel otomatis jika belum ada
db.create_all()
app.run(debug=True)Penjelasan
-
db.create_all(): Kita tidak perlu menulisCREATE TABLEdi SQL manual. Flask-SQLAlchemy akan melihat class model kamu (Mahasiswa,Prodi) dan membuat tabelnya otomatis saat aplikasi pertama kali dijalankan. -
List Data & Unpacking dictionary (
**): Pada baris[{**p.to_dict(), ...}].p.to_dict()mengambil data dasar Prodi.**membongkar dictionary tersebut.- Lalu kita menimpa atau menambah key baru
"mahasiswa".
-
db.sessionadd(): Menaruh data sementara.commit(): Menyimpan data kedalam database. Kalau lupacommit, data tidak akan tersimpan!
Langkah 5: Menjalankan Aplikasi
Jalankan aplikasi kamu dengan perintah:
python app.pykamu akan melihat output Running on http://127.0.0.1:5000.
Cara Tes (Menggunakan Postman):
-
Buat Prodi Dulu (Opsional tapi penting untuk relasi): Karena kita belum buat endpoint POST untuk Prodi, kamu bisa insert manual via Database (phpMyAdmin) ke tabel
prodi:INSERT INTO prodi (name) VALUES ('Teknik Informatika');(Ingat ID nya, misal ID = 1). -
POST Mahasiswa:
- URL:
http://localhost:5000/mahasiswa - Method:
POST - Body (JSON):
request body { "name": "Mahasiswa 1", "npm": "2024250026", "profile_picture": "mahasiswa1.jpg", "prodi_id": 1 } - URL:
-
GET Mahasiswa:
- Buka browser ke
http://localhost:5000/mahasiswa.
- Buka browser ke
Selesai
Kamu telah belajar:
- Menggunakan UV untuk manajemen project.
- Menghubungkan Python dengan MySQL menggunakan SQLAlchemy.
- Melakukan operasi CRUD lengkap.
Langkah Selanjutnya:
Cobalah untuk menambahkan endpoint POST /prodi agar kita bisa menambah program studi langsung dari API.