Membuat Aplikasi CRUD Api NodeJS React
Membuat Aplikasi CRUD Api NodeJS React - Pada tulisan Membuat Aplikasi CRUD Api NodeJS React saya mendokumentasikan percobaan-percobaan kecil terkait Cara Membuat Aplikasi CRUD Api NodeJS React, karena belakangan ini saya mulai tertarik dengan reactjs, nodejs, dan nextjs.
Pertama sekali tentunya kita harus siapkan sebuah backend, untuk menjadi server apinya. Caranya mudah dalam membuat backend ini, yang terpenting anda harus sudah tahu cara menggunakan nodejs dan mengingstapp aplikasinya.
Langkah pertama dalam membuat crud Api Mysql nodeJs dan React
Install packagenya

npm init -y npm install express mysql2 corsTunggu installasi sampai selesai, mungkin agak lama tergantung koneksi anda.
Berikutnya buat file di root backend bernama db.js yang isinya begini:
import mysql from "mysql2" const db = mysql.createConnection({ host: "localhost", user: "root", password: "", database: "school_db" }) db.connect((err) => { if (err) { console.log("Gagal koneksi ke database", err) } else { console.log("Terhubung ke database") } }) export default dbKemudian buat file route didalam directory route di root backend
// ============================================================ // backend/routes/students.js // ROUTER UNTUK CRUD DATA SISWA // ============================================================ // Import modul utama express & koneksi database import express from "express"; import db from "../db.js"; // Buat router instance untuk menangani endpoint /api/students const router = express.Router(); // ============================================================ // GET /api/students — Ambil semua data siswa dari database // ============================================================ // Proses: // 1. Jalankan query SELECT untuk mengambil seluruh isi tabel "students" // 2. Jika error, kirim status 500 dengan pesan error // 3. Jika sukses, kirim hasil dalam format JSON router.get("/", (req, res) => { db.query("SELECT * FROM students", (err, results) => { if (err) return res.status(500).json({ error: err }); res.json(results); // hasil dikirim ke frontend }); }); // ============================================================ // POST /api/students — Tambah siswa baru // ============================================================ // Proses: // 1. Ambil data `name`, `nis`, dan `class` dari body request // 2. Jalankan query INSERT untuk menambah data baru ke database // 3. Ambil kembali data yang baru disimpan (dengan SELECT by ID) // 4. Kembalikan data baru ke frontend sebagai response router.post("/", (req, res) => { const { name, nis, class: className } = req.body; const sql = "INSERT INTO students (name, nis, class) VALUES (?, ?, ?)"; db.query(sql, [name, nis, className], (err, result) => { if (err) return res.status(500).json({ error: err }); // Dapatkan ID siswa baru yang ditambahkan const newId = result.insertId; // Ambil data lengkap siswa yang baru dimasukkan db.query("SELECT * FROM students WHERE id=?", [newId], (err, rows) => { if (err) return res.status(500).json({ error: err }); res.json(rows[0]); // kirim kembali data baru }); }); }); // ============================================================ // PUT /api/students/:id — Edit / Update data siswa // ============================================================ // Proses: // 1. Ambil parameter `id` dari URL dan data baru dari body request // 2. Jalankan query UPDATE untuk memperbarui data siswa // 3. Setelah berhasil, ambil data terbaru dari database // 4. Kembalikan data terbaru ke frontend router.put("/:id", (req, res) => { const { id } = req.params; // ambil ID dari URL const { name, nis, class: className } = req.body; // ambil data dari body const sql = "UPDATE students SET name=?, nis=?, class=? WHERE id=?"; db.query(sql, [name, nis, className, id], (err) => { if (err) return res.status(500).json({ error: err }); // Ambil kembali data siswa setelah diupdate db.query("SELECT * FROM students WHERE id=?", [id], (err, rows) => { if (err) return res.status(500).json({ error: err }); res.json(rows[0]); // kirim hasil update ke frontend }); }); }); // ============================================================ // DELETE /api/students/:id — Hapus data siswa // ============================================================ // Proses: // 1. Ambil parameter `id` dari URL // 2. Jalankan query DELETE untuk menghapus baris sesuai ID // 3. Jika sukses, kirim pesan konfirmasi JSON ke frontend router.delete("/:id", (req, res) => { const { id } = req.params; const sql = "DELETE FROM students WHERE id=?"; db.query(sql, [id], (err) => { if (err) return res.status(500).json({ error: err }); res.json({ message: "Data berhasil dihapus" }); }); }); // ============================================================ // Ekspor router agar bisa dipakai di file server utama (server.js) // ============================================================ export default router;Selanjutnya buat file index.js di root backend
// index.js import express from "express"; import cors from "cors"; import studentsRoute from "./routes/students.js"; const app = express(); app.use(cors()); app.use(express.json()); app.use("/api/students", studentsRoute); const PORT = 5000; app.listen(PORT, () => console.log(`Server berjalan di port ${PORT}`));Sebelum menjalankan servernya buat sebuah database bernama school_db
CREATE DATABASE school_db; USE school_db; CREATE TABLE students ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), nis VARCHAR(50), class VARCHAR(50) );Isi databasenya untuk dummy
INSERT INTO students (name, nis, class) VALUES ('Andi Pratama', '12345', 'XII-A'), ('Siti Nurhaliza', '12346', 'XI-B'), ('Budi Santoso', '12347', 'X-A');Buat Page/StudentPages.jsx
import { useEffect, useState } from "react"; import StudentForm from "../components/StudentForm"; import StudentList from "../components/StudentList"; import { getStudents, addStudent, updateStudent, deleteStudent, } from "../services/studentService"; // Semua fungsi API dipisahkan di file service // agar komponen ini tetap bersih dan mudah dikelola // ===================================================== // Komponen utama untuk halaman siswa // ===================================================== export default function StudentsPage() { // STATE MANAGEMENT // ----------------------------------------------------- // Menyimpan daftar siswa (hasil fetch dari backend) const [students, setStudents] = useState([]); // Menyimpan data siswa yang sedang diedit (jika ada) const [editingStudent, setEditingStudent] = useState(null); // Menyimpan teks pencarian dari input filter const [searchTerm, setSearchTerm] = useState(""); // ===================================================== // 1. Load data awal (GET dari backend) // ----------------------------------------------------- // Saat halaman pertama kali dimuat, ambil semua data siswa useEffect(() => { loadStudents(); }, []); // Fungsi async untuk memanggil API dan memperbarui state const loadStudents = async () => { const data = await getStudents(); // → arah: frontend → backend (GET /api/students) setStudents(data); // data dari backend disimpan ke state }; // ===================================================== // 2. Tambah siswa (POST ke backend) // ----------------------------------------------------- // Dipanggil oleh StudentForm saat user klik tombol "Tambah" // Flow: // - StudentForm kirim data lewat props onAddStudent(newStudent) // - Masuk ke handleAddStudent → panggil addStudent() di service // - Hasil dari backend langsung ditambahkan ke state `students` const handleAddStudent = async (newStudent) => { const added = await addStudent(newStudent); // POST → /api/students // langsung update tampilan tanpa reload setStudents((prev) => [added, ...prev]); }; // ===================================================== // 3. Update siswa (PUT ke backend) // ----------------------------------------------------- // Dipanggil oleh StudentForm saat user klik "Simpan Perubahan" // Flow: // - StudentForm kirim props onUpdateStudent(updatedStudent) // - Masuk ke handleUpdateStudent → panggil updateStudent() di service // - Hasil edit langsung mengganti data lama dalam state const handleUpdateStudent = async (student) => { const updated = await updateStudent(student); // PUT → /api/students/:id // replace data lama dengan yang baru setStudents((prev) => prev.map((s) => (s.id === updated.id ? updated : s)) ); setEditingStudent(null); // keluar dari mode edit }; // ===================================================== // 4. Masuk ke mode edit // ----------------------------------------------------- // Dipanggil oleh StudentList → StudentItem (saat klik tombol Edit) // Data siswa yang diklik dikirim ke StudentForm agar form menampilkan datanya const handleEdit = (student) => { setEditingStudent(student); }; // ===================================================== // 5. Hapus siswa (DELETE ke backend) // ----------------------------------------------------- // Dipanggil dari tombol "Hapus" di StudentList // Flow: // - StudentList kirim props onDelete(id) // - handleDelete kirim DELETE request ke backend // - lalu update state tanpa reload halaman const handleDelete = async (id) => { await deleteStudent(id); // DELETE → /api/students/:id setStudents((prev) => prev.filter((s) => s.id !== id)); // hapus dari state }; // ===================================================== // 6. Filter (pencarian siswa) // ----------------------------------------------------- // Menyaring siswa berdasarkan nama yang diketik di input pencarian const filteredStudents = students.filter((s) => s.name.toLowerCase().includes(searchTerm.toLowerCase()) ); // ===================================================== // 7. Render UI // ----------------------------------------------------- return ( <div style={{ maxWidth: 900, margin: "0 auto", padding: 16 }}> <h1>Aplikasi Data Siswa</h1> {/* Input Pencarian */} <input type="text" placeholder="Cari nama siswa..." value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} // update searchTerm setiap ketikan style={{ width: "100%", padding: "8px", marginBottom: "16px", borderRadius: "6px", border: "1px solid #ccc", }} /> {/* Komponen Form (Tambah/Edit Siswa) Props dikirim agar form tahu kapan mode edit/tambah dan bisa memanggil fungsi dari sini (callback) */} <StudentForm onAddStudent={handleAddStudent} // untuk tambah onUpdateStudent={handleUpdateStudent} // untuk simpan hasil edit editingStudent={editingStudent} // data siswa yang sedang diedit /> {/* Komponen Daftar Siswa Props: - students → daftar hasil filter pencarian - onDelete → fungsi hapus siswa - onEdit → fungsi masuk mode edit */} <StudentList students={filteredStudents} onDelete={handleDelete} onEdit={handleEdit} /> </div> ); }Buat folder components berisi file StudentList.jsx yang berisi code ini
export default function StudentList({ students, onDelete, onEdit }) { if (students.length === 0) return <p>Belum ada data siswa.</p>; return ( <table width="100%" border="1" cellPadding="8"> <thead> <tr> <th>Nama</th> <th>NIS</th> <th>Kelas</th> <th>Aksi</th> </tr> </thead> <tbody> {students.map((s) => ( <tr key={s.id}> <td>{s.name}</td> <td>{s.nis}</td> <td>{s.class}</td> <td> <button onClick={() => onEdit(s)}>Edit</button>{" "} <button onClick={() => onDelete(s.id)}>Hapus</button> </td> </tr> ))} </tbody> </table> ); }didalam components buat juga file StudentItem.jsx berisini code ini
// =========================================================== // 🔹 Komponen StudentItem // ----------------------------------------------------------- // Bertugas menampilkan satu baris data siswa di dalam tabel. // Menerima props dari StudentList untuk menampilkan data, // serta callback onEdit & onDelete agar bisa memanggil fungsi // di komponen induk (StudentsPage). // =========================================================== export default function StudentItem({ index, student, onDelete, onEdit }) { return ( <tr> {/* 🔸 Kolom nomor urut */} <td style={{ border: "1px solid #ddd", padding: 8 }}>{index}</td> {/* 🔸 Kolom nama siswa */} <td style={{ border: "1px solid #ddd", padding: 8 }}> {student.name} </td> {/* 🔸 Kolom NIS */} <td style={{ border: "1px solid #ddd", padding: 8 }}> {student.nis} </td> {/* 🔸 Kolom kelas */} <td style={{ border: "1px solid #ddd", padding: 8 }}> {student.class} </td> {/* 🔸 Kolom aksi (Edit & Hapus) */} <td style={{ border: "1px solid #ddd", padding: 8 }}> {/* Tombol edit: kirim data siswa ke onEdit */} <button style={{ marginRight: 6, backgroundColor: "#4caf50", color: "white", border: "none", padding: "6px 10px", borderRadius: "4px" }} onClick={() => onEdit(student)} > Edit </button> {/* Tombol hapus: kirim id siswa ke onDelete */} <button style={{ backgroundColor: "#f44336", color: "white", border: "none", padding: "6px 10px", borderRadius: "4px" }} onClick={() => onDelete(student.id)} > Hapus </button> </td> </tr> ); }Buat juga file StudentForm.jsx di folder components berisi code ini
// =========================================================== // 🔹 Komponen StudentForm // ----------------------------------------------------------- // Bertanggung jawab untuk: // - Menangani input data siswa (nama, NIS, kelas) // - Menangani mode tambah dan mode edit // - Mengirim data ke parent (StudentsPage) lewat callback: // → onAddStudent() → untuk data baru // → onUpdateStudent() → untuk update data // =========================================================== import { useEffect, useState } from "react"; export default function StudentForm({ onAddStudent, // Callback dari parent untuk menambah siswa baru onUpdateStudent, // Callback dari parent untuk mengupdate data siswa editingStudent, // Objek siswa yang sedang diedit (null jika mode tambah) }) { // State untuk menyimpan isi form const [form, setForm] = useState({ name: "", nis: "", class: "" }); // Efek samping: isi form otomatis ketika kita klik "Edit" useEffect(() => { if (editingStudent) { // Jika ada data yang sedang diedit → isi form dengan data tersebut setForm(editingStudent); } else { // Jika tidak ada yang sedang diedit → kosongkan form setForm({ name: "", nis: "", class: "" }); } }, [editingStudent]); // depend on editingStudent agar bereaksi saat berubah // Handler ketika user mengetik di input const handleChange = (e) => { setForm({ ...form, // salin semua data form lama [e.target.name]: e.target.value, // ubah hanya field yang diketik }); }; // Handler ketika user menekan tombol submit const handleSubmit = (e) => { e.preventDefault(); // cegah reload halaman if (editingStudent) { // Jika sedang mode edit → kirim data ke parent lewat onUpdateStudent() onUpdateStudent(form); } else { // Jika mode tambah → kirim data baru lewat onAddStudent() onAddStudent(form); } // Setelah submit → kosongkan form agar siap input baru setForm({ name: "", nis: "", class: "" }); }; // =========================================================== // UI Bagian Form // =========================================================== return ( <form onSubmit={handleSubmit} style={{ marginBottom: 20, display: "flex", gap: 8, alignItems: "center", }} > <input name="name" placeholder="Nama" value={form.name} onChange={handleChange} required style={{ flex: 1, padding: 6 }} /> <input name="nis" placeholder="NIS" value={form.nis} onChange={handleChange} required style={{ flex: 1, padding: 6 }} /> <input name="class" placeholder="Kelas" value={form.class} onChange={handleChange} required style={{ flex: 1, padding: 6 }} /> {/* Tombol berubah sesuai mode */} <button type="submit" style={{ padding: "8px 12px", backgroundColor: editingStudent ? "#4caf50" : "#2196f3", color: "white", border: "none", borderRadius: "6px", }} > {editingStudent ? "Update" : "Tambah"} </button> </form> ); }Ubah File App.js isi dengan code ini
import StudentsPage from "./pages/StudentPages"; export default function App() { return <StudentsPage />; }Selesai sudah cara Membuat Aplikasi CRUD Api NodeJS React. Semoga bermanfaat.
Komentar
Posting Komentar