Studi Kasus #3: Aplikasi Wisata Indonesia – Membuat Server Express dan Koneksi Database
Halo, calon full-stack developer!
Setelah menyiapkan lingkungan development di Studi Kasus #2, sekarang saatnya kita mulai membangun backend! Kita akan membuat server menggunakan Express.js, menghubungkannya ke database MySQL, dan membuat fungsi-fungsi dasar untuk mengakses data. Server ini akan menjadi "jantung" aplikasi yang melayani permintaan dari frontend React nantinya.
Bayangkan server ini seperti pelayan di restoran. Dia menerima pesanan (request), memasak (memproses data), dan mengirimkan hidangan (response) ke pelanggan (frontend). Yuk, kita buat pelayan kita!
Langkah 1: Masuk ke Folder Backend dan Inisialisasi
Buka terminal/command prompt, lalu arahkan ke folder proyek utama wisata-indonesia. Masuk ke folder backend yang sudah kita buat sebelumnya:
cd backend
Pastikan di folder ini sudah ada file package.json dari inisialisasi sebelumnya. Jika belum, jalankan:
npm init -y
Sekarang kita akan menginstal semua paket yang dibutuhkan.
Langkah 2: Instalasi Paket yang Diperlukan
Jalankan perintah berikut untuk menginstal paket-paket:
npm install express mysql2 cors dotenv multer
Penjelasan masing-masing paket:
- express – framework web untuk membuat server dan API.
- mysql2 – driver MySQL untuk Node.js (mendukung promise).
- cors – middleware untuk mengizinkan permintaan dari domain lain (agar frontend React bisa mengakses API).
- dotenv – untuk membaca konfigurasi dari file
.env(seperti password database). - multer – middleware untuk menangani upload file (nanti kita pakai untuk upload gambar).
--save-dev. Tapi untuk paket-paket di atas, kita butuh semuanya di production juga.
Setelah selesai, akan ada folder node_modules dan file package-lock.json. Ini normal.
Langkah 3: Membuat File .env untuk Konfigurasi Database
File .env digunakan untuk menyimpan variabel lingkungan seperti kredensial database. Ini penting agar data sensitif tidak tercampur dengan kode.
Buat file baru di folder backend dengan nama .env. Isi dengan konfigurasi berikut (sesuaikan dengan password dan host MySQL kamu):
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=root
DB_NAME=wisata_db
PORT=3000
Jika pakai XAMPP, biasanya password root kosong. Tapi sebaiknya isi dengan password yang sudah kamu set.
.env ke Git! Tambahkan .env ke file .gitignore.
Buat file .gitignore di folder backend (jika belum ada) dan isi dengan:
node_modules/
.env
Langkah 4: Membuat File Konfigurasi Database
Kita akan membuat file khusus untuk mengelola koneksi database. Buat folder config di dalam backend, lalu buat file db.js.
Struktur folder:
backend/
├── config/
│ └── db.js
├── node_modules/
├── .env
├── .gitignore
├── package.json
└── package-lock.json
Isi file config/db.js:
const mysql = require('mysql2');
require('dotenv').config();
// Buat pool koneksi (lebih efisien daripada koneksi tunggal)
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
// Ubah pool menjadi promise-based agar bisa pakai async/await
const promisePool = pool.promise();
module.exports = promisePool;
Penjelasan:
require('dotenv').config()membaca file.envdan memasukkan nilainya keprocess.env.mysql.createPoolmembuat kumpulan koneksi, lebih baik daripada membuat koneksi setiap kali.pool.promise()mengembalikan versi promise dari pool, sehingga kita bisa menggunakanasync/await.- Kita
exportpromisePool agar bisa digunakan di file lain.
Langkah 5: Membuat Server Express
Buat file app.js di folder backend. Ini akan menjadi file utama server kita.
const express = require('express');
const cors = require('cors');
require('dotenv').config();
const app = express();
const port = process.env.PORT || 3000;
// Middleware
app.use(cors()); // mengizinkan akses dari frontend
app.use(express.json()); // membaca request body dalam format JSON
app.use(express.urlencoded({ extended: true })); // membaca form-urlencoded
// Route sederhana untuk testing
app.get('/', (req, res) => {
res.json({ message: 'Server Wisata Indonesia berjalan!' });
});
// Jalankan server
app.listen(port, () => {
console.log(`🚀 Server berjalan di http://localhost:${port}`);
});
Jalankan server dengan:
node app.js
Buka browser ke http://localhost:3000. Harusnya muncul JSON:
{ "message": "Server Wisata Indonesia berjalan!" }
Selamat! Server pertama kita sudah hidup. 🎉
Langkah 6: Membuat Fungsi Query Dasar (Contoh: Categories)
Sekarang kita akan membuat fungsi untuk mengambil data dari tabel categories. Buat folder controllers dan routes untuk menjaga kode tetap rapi.
Pertama, buat file controllers/categoryController.js:
const db = require('../config/db');
// Mendapatkan semua kategori
const getAllCategories = async (req, res) => {
try {
const [rows] = await db.query('SELECT * FROM categories ORDER BY id DESC');
res.json(rows);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Gagal mengambil data kategori' });
}
};
// Mendapatkan satu kategori berdasarkan ID
const getCategoryById = async (req, res) => {
const { id } = req.params;
try {
const [rows] = await db.query('SELECT * FROM categories WHERE id = ?', [id]);
if (rows.length === 0) {
return res.status(404).json({ error: 'Kategori tidak ditemukan' });
}
res.json(rows[0]);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Gagal mengambil data kategori' });
}
};
// Menambah kategori baru
const createCategory = async (req, res) => {
const { name, slug, description } = req.body;
if (!name || !slug) {
return res.status(400).json({ error: 'Nama dan slug harus diisi' });
}
try {
const [result] = await db.query(
'INSERT INTO categories (name, slug, description) VALUES (?, ?, ?)',
[name, slug, description]
);
res.status(201).json({ id: result.insertId, name, slug, description });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Gagal menambah kategori' });
}
};
// Update kategori
const updateCategory = async (req, res) => {
const { id } = req.params;
const { name, slug, description } = req.body;
try {
const [result] = await db.query(
'UPDATE categories SET name = ?, slug = ?, description = ? WHERE id = ?',
[name, slug, description, id]
);
if (result.affectedRows === 0) {
return res.status(404).json({ error: 'Kategori tidak ditemukan' });
}
res.json({ message: 'Kategori berhasil diupdate' });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Gagal mengupdate kategori' });
}
};
// Hapus kategori
const deleteCategory = async (req, res) => {
const { id } = req.params;
try {
const [result] = await db.query('DELETE FROM categories WHERE id = ?', [id]);
if (result.affectedRows === 0) {
return res.status(404).json({ error: 'Kategori tidak ditemukan' });
}
res.json({ message: 'Kategori berhasil dihapus' });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Gagal menghapus kategori' });
}
};
module.exports = {
getAllCategories,
getCategoryById,
createCategory,
updateCategory,
deleteCategory
};
Penjelasan:
- Kita menggunakan
await db.query()untuk menjalankan query SQL. Hasilnya adalah array dua elemen:[rows, fields]. Kita ambilrows. - Query parameter menggunakan placeholder
?untuk menghindari SQL injection. - Error handling dengan try-catch, dan mengirim respons JSON yang sesuai.
Selanjutnya, buat file routes/categoryRoutes.js untuk mendefinisikan endpoint:
const express = require('express');
const router = express.Router();
const categoryController = require('../controllers/categoryController');
router.get('/', categoryController.getAllCategories);
router.get('/:id', categoryController.getCategoryById);
router.post('/', categoryController.createCategory);
router.put('/:id', categoryController.updateCategory);
router.delete('/:id', categoryController.deleteCategory);
module.exports = router;
Terakhir, kita daftarkan route tersebut di app.js.
Tambahkan baris berikut di app.js setelah middleware dan sebelum app.listen:
const categoryRoutes = require('./routes/categoryRoutes');
app.use('/api/categories', categoryRoutes);
Jadi, semua endpoint kategori akan memiliki prefix /api/categories.
Langkah 7: Menguji API dengan Postman
Pastikan server sudah berjalan (dengan node app.js). Buka Postman dan coba beberapa request:
- GET
http://localhost:3000/api/categories– mengambil semua kategori (harusnya array kosong atau data dari Studi Kasus #1). - POST
http://localhost:3000/api/categoriesdengan body JSON (pilih raw JSON):{ "name": "Wisata Alam", "slug": "wisata-alam", "description": "Tempat wisata alam seperti pantai, gunung, dll." } - GET lagi untuk memastikan data sudah masuk.
- GET
http://localhost:3000/api/categories/1– mengambil kategori dengan ID 1. - PUT
http://localhost:3000/api/categories/1dengan body JSON untuk update. - DELETE
http://localhost:3000/api/categories/1untuk menghapus.
Pastikan semua berjalan dengan baik. Jika ada error, periksa kembali kode atau koneksi database.
📁 Struktur Folder Backend Saat Ini
backend/
├── config/
│ └── db.js
├── controllers/
│ └── categoryController.js
├── routes/
│ └── categoryRoutes.js
├── node_modules/
├── .env
├── .gitignore
├── app.js
├── package.json
└── package-lock.json
Penjelasan Tambahan
- Mengapa menggunakan pool? – Pool lebih efisien karena koneksi MySQL dapat digunakan kembali. Tanpa pool, setiap request akan membuat koneksi baru dan menutupnya, yang lambat.
- Mengapa query parameter menggunakan
?? – Untuk mencegah SQL injection, jangan pernah menggabungkan nilai langsung ke string SQL. - Middleware cors: Frontend React yang berjalan di domain berbeda (misal localhost:5173) akan bisa mengakses API ini.
- Middleware express.json: Memungkinkan kita membaca JSON dari body request.
Langkah Selanjutnya
Di Studi Kasus #4, kita akan membuat API untuk tabel-tabel lain (destinations, accommodations, transportations) dan mengelola relasi dengan kategori. Kita juga akan mulai menggunakan multer untuk upload gambar.
Pastikan server berjalan dan semua endpoint kategori berfungsi sebelum lanjut. Jika ada kendala, tulis di komentar!
Sampai jumpa di tutorial berikutnya! 👋😊
Ditulis dengan ❤️ untuk para pengembang yang ingin membangun aplikasi wisata.