Mengapa desain basis data dan desain API harus dilakukan bersama?
Dalam dunia pengembangan aplikasi, keselarasan antara desain basis data dan desain API sangat penting. Artikel ini menjelajahi mengapa kedua elemen ini harus dikembangkan secara bersamaan, menggunakan perumpamaan sederhana dan contoh praktis untuk menggambarkan kesalingterkaitan mereka.
Kamu sedang membuat sandwich selai kacang dan jeli. Kamu memiliki dua slice roti (aplikasi front-end dan server back-end), dan selai kacang dan jeli (database dan API).
Jika kamu tidak menyebarkannya dalam urutan yang benar atau menggunakan jumlah yang salah, sandwich bisa menjadi bencana. Hal yang sama berlaku untuk desain database dan API. Mereka memerlukan harmoni yang sempurna jika kamu ingin aplikasimu berjalan dengan baik.
Mari kita bahas bagaimana desain database dan desain API lebih terhubung daripada yang kamu pikirkan. Saat kamu mengembangkan API, kamu pada dasarnya membangun jembatan untuk mengakses data yang disimpan dalam database. Dan seperti dalam setiap hubungan yang baik, komunikasi adalah kunci.
Mari kita lihat bagaimana kamu bisa menghubungkan desain database dan desain API menggunakan contoh konkret dengan beberapa kode nyata. Kita akan membahas beberapa konsep langkah demi langkah untuk benar-benar memahaminya. Persiapkan diri! Kita akan menyelam ke dalam PB&J pengembangan.

Skema & Endpoint: Memetakan Databasemu ke Rute API
Yang pertama kita butuhkan adalah skema untuk database. Misalkan kita membuat API untuk platform blogging sederhana. Berikut mungkin seperti apa skema database untuk dua entitas utama: Pengguna dan Postingan.
Desain Database (Skema):
-- Tabel Pengguna
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Tabel Postingan
CREATE TABLE posts (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
Dalam desain ini:
- Tabel
users
menyimpan informasi tentang pengguna. - Tabel
posts
menyimpan postingan blog dan memiliki kunci asing (user_id
) yang merujuk ke tabelusers
(menunjukkan hubungan antara pengguna dan postingannya).
Desain API (Endpoint):
Sekarang, saat mendesain API untuk berinteraksi dengan data ini, kita perlu memaparkan endpoint untuk berinteraksi dengan baik pengguna dan postingan.
- GET
/users/{id}
β Mendapatkan pengguna tertentu. - POST
/users
β Membuat pengguna baru. - GET
/users/{id}/posts
β Mendapatkan semua postingan oleh pengguna. - POST
/posts
β Membuat postingan baru.
// Langkah 1: Impor modul yang diperlukan
const express = require('express');
const app = express();
const mysql = require('mysql'); // Impor modul MySQL untuk menyambung ke database
const bodyParser = require('body-parser');
// Langkah 2: Setel koneksi ke database MySQL
const db = mysql.createConnection({
host: 'localhost',
user: 'root', // Nama pengguna MySQL
password: 'password', // Kata sandi MySQL
database: 'blog_db' // Nama database yang kita gunakan (dalam hal ini, 'blog_db')
});
// Langkah 3: Perangkat tengah untuk mengurai permintaan JSON
app.use(bodyParser.json()); // Ini memungkinkan kita mengakses `req.body` sebagai objek JSON
// Langkah 4: Endpoint untuk mendapatkan detail pengguna berdasarkan ID mereka
// Ketika permintaan dibuat ke '/users/:id', rute ini akan mengambil pengguna dari database berdasarkan ID mereka
app.get('/users/:id', (req, res) => {
const userId = req.params.id; // Ambil ID pengguna dari parameter URL
// Query database untuk mendapatkan pengguna dengan ID yang ditentukan
db.query('SELECT * FROM users WHERE id = ?', [userId], (err, result) => {
if (err) {
// Jika terjadi kesalahan database, kirim respons kesalahan 500
return res.status(500).send('Kesalahan database');
}
if (result.length === 0) {
// Jika tidak ditemukan pengguna dengan ID yang diberikan, kirim respons 404
return res.status(404).send('Pengguna tidak ditemukan');
}
// Kirim data pengguna sebagai respons JSON
res.json(result[0]);
});
});
// Endpoint
// Langkah 5: Endpoint untuk mendapatkan semua postingan oleh pengguna tertentu
// Rute ini mengembalikan semua postingan yang ditulis oleh pengguna, menggunakan ID pengguna mereka
app.get('/users/:id/posts', (req, res) => {
const userId = req.params.id; // Ekstrak ID pengguna dari URL
// Query database untuk mendapatkan semua postingan di mana user_id sesuai dengan ID pengguna yang ditentukan
db.query('SELECT * FROM posts WHERE user_id = ?', [userId], (err, result) => {
if (err) {
// Tangani kesalahan database dengan mengirim respons kesalahan 500
return res.status(500).send('Kesalahan database');
}
// Kirim daftar postingan sebagai respons JSON
res.json(result);
});
});
// Langkah 6: Endpoint untuk membuat postingan baru
// Rute ini menerima data dari body permintaan untuk membuat postingan baru
app.post('/posts', (req, res) => {
const { user_id, title, content } = req.body; // Ekstrak data postingan dari body permintaan
// Query untuk menyisipkan postingan baru ke tabel 'posts'
db.query(
'INSERT INTO posts (user_id, title, content) VALUES (?, ?, ?)',
[user_id, title, content], // Nilai yang akan disisipkan ke tabel
(err, result) => {
if (err) {
// Jika terjadi kesalahan database, kirim respons kesalahan 500
return res.status(500).send('Kesalahan database');
}
// Kirim respons yang mengkonfirmasi pembuatan postingan dengan ID postingan baru
res.status(201).send(`Postingan dibuat dengan ID: ${result.insertId}`);
}
);
});
// Langkah 7: Mulai server dan dengarkan pada port 3000
app.listen(3000, () => {
// Log ke konsol ketika server berhasil dimulai
console.log('API berjalan di http://localhost:3000');
});
Apa yang Kita Lakukan Di Sini:
1. /users/:id
β Mendapatkan Pengguna oleh ID
- Endpoint ini mengambil detail pengguna tertentu dari database menggunakan
id
mereka. - Kueri SQL
SELECT * FROM users WHERE id = ?
mengambil informasi pengguna dari tabelusers
.
// Mendapatkan pengguna oleh ID
app.get('/users/:id', (req, res) => {
const userId = req.params.id; // Ekstrak ID pengguna dari parameter URL
// Query database untuk mendapatkan pengguna dengan ID yang ditentukan
db.query('SELECT * FROM users WHERE id = ?', [userId], (err, result) => {
if (err) {
// Tangani kesalahan database dengan mengirim respons kesalahan 500
return res.status(500).send('Kesalahan database');
}
if (result.length === 0) {
// Jika tidak ditemukan pengguna dengan ID yang diberikan, kirim respons 404
return res.status(404).send('Pengguna tidak ditemukan');
}
// Kirim data pengguna sebagai respons JSON
res.json(result[0]);
});
});
Query Database:
- SQL:
SELECT * FROM users WHERE id = ?
- Ini mengambil semua detail (
*
) dari pengguna denganid
yang diberikan. - Tanda
?
adalah placeholder untuk nilaiid
sebenarnya yang berasal darireq.params.id
(parameter URL).
2. /users/:id/posts
β Mendapatkan Semua Postingan oleh Pengguna
- Endpoint ini mengambil semua postingan yang dimiliki oleh pengguna tertentu, menggunakan kunci asing
user_id
di tabelposts
. - Kueri SQL
SELECT * FROM posts WHERE user_id = ?
mengambil postingan yang terkait denganuser_id
.
// Mendapatkan postingan oleh pengguna
app.get('/users/:id/posts', (req, res) => {
const userId = req.params.id; // Ekstrak ID pengguna dari URL
// Query database untuk mendapatkan semua postingan oleh pengguna yang ditentukan
db.query('SELECT * FROM posts WHERE user_id = ?', [userId], (err, result) => {
if (err) {
// Tangani kesalahan database dengan mengirim respons kesalahan 500
return res.status(500).send('Kesalahan database');
}
// Kirim daftar postingan sebagai respons JSON
res.json(result);
});
});
Query Database:
- SQL:
SELECT * FROM posts WHERE user_id = ?
- Ini mengambil semua postingan dari tabel
posts
di manauser_id
sesuai denganid
dari tabelusers
. user_id
dalam tabel posts adalah kunci asing yang menghubungkan postingan ke pengguna tertentu.
3. POST /posts
β Membuat Postingan Baru
- Endpoint ini membuat postingan blog baru. Memerlukan
user_id
,title
, dancontent
dari body permintaan, lalu menyisipkan data tersebut ke tabelposts
di database. - Kueri SQL
INSERT INTO posts (user_id, title, content) VALUES (?, ?, ?)
digunakan untuk menyisipkan postingan ke database.
// Membuat postingan baru
app.post('/posts', (req, res) => {
const { user_id, title, content } = req.body; // Ekstrak data postingan dari body permintaan
// Query untuk menyisipkan postingan baru ke tabel 'posts'
db.query(
'INSERT INTO posts (user_id, title, content) VALUES (?, ?, ?)',
[user_id, title, content], // Nilai yang akan disisipkan ke tabel
(err, result) => {
if (err) {
// Jika terjadi kesalahan database, kirim respons kesalahan 500
return res.status(500).send('Kesalahan database');
}
// Kirim respons yang mengkonfirmasi pembuatan postingan dengan ID postingan baru
res.status(201).send(`Postingan dibuat dengan ID: ${result.insertId}`);
}
);
});
Query Database:
- SQL:
INSERT INTO posts (user_id, title, content) VALUES (?, ?, ?)
- Ini menyisipkan data postingan baru ke tabel
posts
, menghubungkannya dengan pengguna melaluiuser_id
. - Placeholder
?
diganti dengan nilai sebenarnya (user_id
,title
,content
) darireq.body
.
Recap: Interaksi API dan Database
/users/:id
: Mengambil informasi pengguna berdasarkan ID. Menggunakan kueriSELECT
untuk mengambil data dari tabelusers
berdasarkan ID pengguna./users/:id/posts
: Mengambil semua postingan oleh pengguna tertentu. Menggunakan kunci asinguser_id
untuk menemukan postingan yang terkait dengan pengguna di tabelposts
.POST /posts
: Membuat postingan baru dan menghubungkannya dengan pengguna menggunakanuser_id
. Menjalankan kueriINSERT
untuk menyimpan postingan baru di tabelposts
.
Endpoint API Express.js berinteraksi langsung dengan database MySQL dengan menanyakan dan memanipulasi data menggunakan kueri SQL. Hubungan antara API dan database sangat terpadu, memungkinkan API untuk menjalankan operasi CRUD dengan lancar.
Dengan mengikuti struktur ini, kita memetakan tabel database langsung ke endpoint API. Semua tentang menyamakan cara database menyimpan data dengan cara API menyajikan data.
Hubungan: API Harus Mencerminkan Database
Di database, kita memiliki hubungan satu-ke-banyak: satu pengguna bisa memiliki banyak postingan. user_id
di tabel posts
mewakili kunci asing yang menghubungkan postingan ke pengguna tertentu.
Untuk mencerminkan hubungan ini dalam API, kita perlu menggabungkan tabel posts
dan users
untuk mengambil data yang relevan, seperti nama pengguna yang membuat setiap postingan.
Contoh API dengan Hubungan (Menggunakan JOIN)
Ambil Postingan dengan Informasi Pengguna (Menggunakan JOIN)
// Mendapatkan semua postingan untuk pengguna, termasuk nama pengguna mereka
app.get('/users/:id/posts', (req, res) => {
const userId = req.params.id;
db.query(
'SELECT posts.*, users.username FROM posts JOIN users ON posts.user_id = users.id WHERE posts.user_id = ?',
[userId],
(err, result) => {
if (err) return res.status(500).send('Kesalahan database');
res.json(result); // Mengembalikan postingan beserta nama pengguna dari tabel users
}
);
});
Penjelasan:
- Rute:
/users/:id/posts
- Interaksi Database: Kita menggunakan SQL
JOIN
untuk menggabungkan tabelposts
danusers
. Kita memilih semua kolom dari tabelposts
(posts.*
), dan juga memilih kolomusername
dari tabelusers
. - Respons: API mengembalikan postingan yang terkait dengan pengguna bersama dengan
username
pengguna yang membuat setiap postingan.
Tipe Data: Pilihlah Bijak!
Saat merancang API, kamu harus mempertimbangkan bagaimana tipe data di database akan dikembalikan dan diformat. Sebagai contoh, kolom created_at
baik di tabel users
dan posts
mungkin disimpan sebagai timestamp di database. Namun, mengirimkan timestamp mentah ke klien mungkin tidak ramah pengguna.
Kita perlu memformat timestamp ini menjadi format yang bisa dibaca manusia sebelum mengembalikannya.
Contoh API dengan Penyusunan Ulang Timestamp
Format Lapangan created_at
(untuk Kemudahan Membaca)
// Mendapatkan semua postingan untuk pengguna, dengan timestamp created_at yang diformat
app.get('/users/:id/posts', (req, res) => {
const userId = req.params.id;
db.query('SELECT * FROM posts WHERE user_id = ?', [userId], (err, result) => {
if (err) return res.status(500).send('Kesalahan database');
// Format timestamp created_at menjadi format yang mudah dibaca
result.forEach(post => {
post.created_at = new Date(post.created_at).toLocaleString(); // Format timestamp
});
// Kirim postingan dengan timestamp yang diformat
res.json(result);
});
});
Penjelasan:
- Rute:
/users/:id/posts
- Interaksi Database: Kita menanyakan tabel
posts
untuk mendapatkan semua postingan untuk pengguna. - Respons: Sebelum mengembalikan postingan, kita mengulangi hasil dan memformat timestamp
created_at
menggunakan metodeDate().toLocaleString()
JavaScript. Ini memastikan timestamp mudah dibaca (misalnya, "23 April 2025, 16:30").
Menutup: Sandwich yang Sempurna
Sama seperti membuat sandwich yang baik, kamu harus menyeimbangkan dengan benar saat mendesain database dan API. Berikut ringkasannya:
- Skema = Gambaran Kerja: Skema database mu secara langsung mempengaruhi endpoint API mu.
- Hubungan = Koneksi: Pastikan API mu menghormati hubungan antar entitas (misalnya,
user_id
danposts
). - Tipe Data = Padankan: Respons API harus sesuai dengan desain database mu, seperti memformat timestamp dengan benar.
Membangun API bisa menjadi tantangan, terutama ketika kamu harus memastikan semuanya tersinkronisasi β dari database SQL hingga desain API. Kamu tidak ingin API mu mengirim data dalam format yang tidak diharapkan, dan kamu pasti tidak menginginkan nama yang tidak cocok antara tabel database mu dan endpoint API. Inilah tempat EchoAPI masuk.
Bagaimana EchoAPI Membantu Sinkronisasi SQL dan Desain API: Konsistensi adalah Kunci

EchoAPI adalah alat yang kuat yang dapat membantu mengisi celah antara database dan API mu, memastikan mereka berbicara dalam bahasa yang sama. Ini mengautomasi banyak aspek dari proses desain, memastikan bahwa skema database mu dan endpoint API tetap sinkron.
EchoAPI membantu menjaga desain API dan database mu sejalan. Dengan membaca langsung dari skema SQL mu, ia dapat secara otomatis membentuk endpoint API mu untuk mencocokkan struktur yang telah kamu tentukan. Ini berarti kurangnya ketidakδΈθ΄an, sinkronisasi yang lebih baik antara backend dan frontend, dan jauh lebih sedikit waktu yang dihabiskan untuk meragukan nama bidang atau memperbaiki tipe data yang tidak cocok.
Dengan EchoAPI, SQL mu dan API tumbuh bersama secara alami β tanpa usaha tambahan yang diperlukan, hanya desain yang bersih dan dapat diprediksi dari awal.
Jika kamu ingin belajar cara menggunakan EchoAPI untuk mengoptimalkan proses desain API mu dan menjamin sinkronisasi antara database dan API mu, ikuti terus. Kita akan menyelami bagaimana menerapkan alat ini dan membimbingmu melalui contoh dunia nyata!