Monday

18-08-2025 Vol 19

Day 16/200 (Full stack)

Day 16/200 (Full Stack): Membangun Aplikasi CRUD dengan React dan Node.js – Panduan Langkah Demi Langkah

Selamat datang kembali di perjalanan 200 hari full-stack development saya! Hari ini, kita akan menyelami proyek yang sangat penting: membangun aplikasi CRUD (Create, Read, Update, Delete) sederhana menggunakan React untuk frontend dan Node.js dengan Express untuk backend. Proyek ini adalah fondasi penting untuk banyak aplikasi web modern dan akan memberi Anda pemahaman praktis tentang bagaimana kedua teknologi ini bekerja sama. Bersiaplah untuk menyelam lebih dalam dan membangun sesuatu yang bermanfaat!

Daftar Isi

  1. Pendahuluan: Mengapa CRUD Penting?
  2. Menyiapkan Lingkungan Pengembangan
    1. Menginstal Node.js dan npm (atau Yarn)
    2. Membuat Direktori Proyek
    3. Menginisialisasi Frontend (React)
    4. Menginisialisasi Backend (Node.js/Express)
  3. Membangun Backend dengan Node.js dan Express
    1. Membuat Server Express
    2. Menentukan Model Data (Misalnya, Menggunakan Mongoose dengan MongoDB)
    3. Membuat Endpoint API untuk Operasi CRUD
      1. Endpoint CREATE (POST)
      2. Endpoint READ (GET)
      3. Endpoint UPDATE (PUT/PATCH)
      4. Endpoint DELETE (DELETE)
    4. Middleware untuk Validasi dan Keamanan
    5. Uji Backend dengan Postman atau Insomnia
  4. Membangun Frontend dengan React
    1. Membuat Komponen React
    2. Menggunakan `useState` dan `useEffect` untuk Manajemen State dan Efek Samping
    3. Mengambil Data dari Backend (Menggunakan `fetch` atau Axios)
    4. Menampilkan Data dalam Daftar
    5. Membuat Formulir untuk Membuat dan Memperbarui Data
    6. Menangani Pengiriman Formulir dan Pembaruan State
    7. Menambahkan Fungsionalitas Delete
    8. Penanganan Error dan Umpan Balik Pengguna
  5. Menghubungkan Frontend dan Backend
    1. Mengkonfigurasi Permintaan CORS
    2. Memastikan Komunikasi yang Benar Antara Frontend dan Backend
  6. Peningkatan Lebih Lanjut dan Pertimbangan Desain
    1. Validasi Input yang Lebih Baik
    2. Pagination untuk Daftar Panjang
    3. Styling dengan CSS atau Library UI (Misalnya, Material UI, Bootstrap)
    4. Autentikasi dan Otorisasi
    5. Penerapan (Deployment) Aplikasi
  7. Kesimpulan: Refleksi dan Langkah Selanjutnya

1. Pendahuluan: Mengapa CRUD Penting?

CRUD adalah singkatan dari Create, Read, Update, dan Delete. Operasi ini adalah pilar utama dari banyak aplikasi web. CRUD memungkinkan pengguna untuk mengelola data, berinteraksi dengan database, dan membangun aplikasi dinamis. Bayangkan sebuah aplikasi to-do list: Anda perlu membuat tugas baru (Create), melihat daftar tugas Anda (Read), mengedit tugas yang ada (Update), dan menghapus tugas yang sudah selesai (Delete). Contoh lain termasuk sistem manajemen inventaris, aplikasi media sosial, dan bahkan sistem manajemen konten (CMS). Memahami CRUD adalah fondasi penting untuk menjadi seorang full-stack developer.

2. Menyiapkan Lingkungan Pengembangan

Sebelum kita mulai, pastikan Anda memiliki lingkungan pengembangan yang disiapkan dengan benar. Ini akan memastikan bahwa Anda dapat menjalankan kode Anda tanpa masalah.

2.1. Menginstal Node.js dan npm (atau Yarn)

Node.js adalah lingkungan runtime JavaScript yang memungkinkan Anda menjalankan JavaScript di sisi server. npm (Node Package Manager) adalah manajer paket yang disertakan dengan Node.js dan digunakan untuk menginstal dan mengelola dependensi proyek Anda. Alternatif populer untuk npm adalah Yarn. Ikuti langkah-langkah berikut untuk menginstal Node.js dan npm:

  1. Unduh Node.js: Kunjungi situs web Node.js dan unduh versi LTS (Long Term Support) yang direkomendasikan.
  2. Instal Node.js: Jalankan installer yang diunduh dan ikuti instruksi di layar.
  3. Verifikasi Instalasi: Buka terminal atau command prompt dan jalankan perintah berikut:
    • node -v (untuk memeriksa versi Node.js)
    • npm -v (untuk memeriksa versi npm)

    Anda akan melihat nomor versi jika instalasi berhasil.

Untuk menginstal Yarn (opsional):

  1. Instal Yarn secara global: Jalankan perintah berikut di terminal:
    • npm install -g yarn
  2. Verifikasi Instalasi: Jalankan perintah berikut:
    • yarn -v (untuk memeriksa versi Yarn)

2.2. Membuat Direktori Proyek

Buat direktori proyek untuk menyimpan semua file terkait aplikasi CRUD Anda. Buka terminal dan jalankan perintah berikut (ganti “crud-app” dengan nama pilihan Anda):

mkdir crud-app
cd crud-app

2.3. Menginisialisasi Frontend (React)

Gunakan Create React App untuk membuat proyek React dengan cepat. Di dalam direktori proyek Anda, jalankan perintah berikut:

npx create-react-app frontend

Ini akan membuat direktori bernama “frontend” dan menyiapkan proyek React dasar. Setelah selesai, navigasikan ke direktori frontend:

cd frontend

2.4. Menginisialisasi Backend (Node.js/Express)

Kembali ke direktori proyek utama Anda (crud-app) dan buat direktori untuk backend:

cd ..
mkdir backend
cd backend

Inisialisasi proyek Node.js baru dengan perintah berikut:

npm init -y

Ini akan membuat file `package.json` dengan pengaturan default. Selanjutnya, instal Express, framework web Node.js yang akan kita gunakan:

npm install express cors mongoose

Kita juga menginstal `cors` untuk menangani permintaan lintas asal dan `mongoose` untuk berinteraksi dengan MongoDB.

3. Membangun Backend dengan Node.js dan Express

Sekarang, mari kita bangun backend kita. Kita akan menggunakan Express untuk membuat server dan menentukan API endpoint untuk operasi CRUD.

3.1. Membuat Server Express

Buat file bernama `index.js` di dalam direktori backend Anda dan tambahkan kode berikut:


const express = require('express');
const cors = require('cors');
const mongoose = require('mongoose');

const app = express();
const port = process.env.PORT || 5000;

app.use(cors());
app.use(express.json()); // for parsing application/json
app.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded

// MongoDB Connection
mongoose.connect('mongodb://127.0.0.1:27017/crudapp', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
})
.then(() => console.log('Connected to MongoDB'))
.catch(err => console.error('MongoDB connection error:', err));


app.listen(port, () => {
  console.log(`Server is running on port: ${port}`);
});

Kode ini melakukan hal berikut:

  • Mengimpor modul yang diperlukan (Express, CORS, Mongoose).
  • Membuat instance aplikasi Express.
  • Menentukan port untuk server (menggunakan variabel lingkungan atau default ke 5000).
  • Menggunakan middleware `cors` untuk mengaktifkan permintaan lintas asal.
  • Menggunakan middleware `express.json()` dan `express.urlencoded()` untuk menguraikan badan permintaan JSON dan URL-encoded.
  • Menghubungkan ke database MongoDB. Pastikan Anda memiliki MongoDB yang berjalan di mesin Anda. Anda mungkin perlu menyesuaikan string koneksi.
  • Memulai server dan mencetak pesan ke konsol.

Tambahkan skrip “start” ke file `package.json` Anda:


{
  "name": "backend",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "mongoose": "^6.0.5"
  }
}

Sekarang Anda dapat menjalankan server dengan perintah:

npm start

3.2. Menentukan Model Data (Misalnya, Menggunakan Mongoose dengan MongoDB)

Mongoose adalah library yang menyediakan cara elegan untuk berinteraksi dengan MongoDB. Mari kita definisikan model data untuk aplikasi CRUD kita. Misalnya, kita akan membuat model untuk “Task”.

Buat direktori bernama `models` di dalam direktori backend Anda, dan di dalam direktori `models`, buat file bernama `Task.js` dengan konten berikut:


const mongoose = require('mongoose');

const taskSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true
  },
  description: {
    type: String
  },
  completed: {
    type: Boolean,
    default: false
  }
});

module.exports = mongoose.model('Task', taskSchema);

Kode ini mendefinisikan skema Mongoose untuk Task, dengan properti `title` (wajib), `description`, dan `completed` (default ke false).

3.3. Membuat Endpoint API untuk Operasi CRUD

Sekarang, mari kita buat endpoint API untuk operasi CRUD. Kita akan membuat endpoint untuk membuat, membaca, memperbarui, dan menghapus tugas.

Di dalam `index.js`, tambahkan kode berikut:

3.3.1. Endpoint CREATE (POST)


const Task = require('./models/Task'); // Import the Task model

// Create a new task
app.post('/tasks', async (req, res) => {
  try {
    const task = new Task(req.body);
    const savedTask = await task.save();
    res.status(201).json(savedTask);
  } catch (err) {
    res.status(400).json({ message: err.message });
  }
});

Endpoint ini menangani permintaan POST ke `/tasks`, membuat instance Task baru menggunakan data dari body permintaan, menyimpannya ke database, dan mengembalikan tugas yang disimpan.

3.3.2. Endpoint READ (GET)


// Get all tasks
app.get('/tasks', async (req, res) => {
  try {
    const tasks = await Task.find();
    res.json(tasks);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

// Get a single task by ID
app.get('/tasks/:id', async (req, res) => {
  try {
    const task = await Task.findById(req.params.id);
    if (!task) {
      return res.status(404).json({ message: 'Task not found' });
    }
    res.json(task);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

Endpoint ini menangani permintaan GET ke `/tasks` (untuk mendapatkan semua tugas) dan `/tasks/:id` (untuk mendapatkan satu tugas berdasarkan ID).

3.3.3. Endpoint UPDATE (PUT/PATCH)


// Update a task
app.put('/tasks/:id', async (req, res) => {
  try {
    const task = await Task.findByIdAndUpdate(req.params.id, req.body, { new: true });
    if (!task) {
      return res.status(404).json({ message: 'Task not found' });
    }
    res.json(task);
  } catch (err) {
    res.status(400).json({ message: err.message });
  }
});

Endpoint ini menangani permintaan PUT ke `/tasks/:id`, memperbarui tugas dengan ID yang diberikan menggunakan data dari body permintaan, dan mengembalikan tugas yang diperbarui. `new: true` mengembalikan dokumen yang diperbarui.

3.3.4. Endpoint DELETE (DELETE)


// Delete a task
app.delete('/tasks/:id', async (req, res) => {
  try {
    const task = await Task.findByIdAndDelete(req.params.id);
    if (!task) {
      return res.status(404).json({ message: 'Task not found' });
    }
    res.json({ message: 'Task deleted' });
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

Endpoint ini menangani permintaan DELETE ke `/tasks/:id`, menghapus tugas dengan ID yang diberikan, dan mengembalikan pesan sukses.

3.4. Middleware untuk Validasi dan Keamanan (Contoh)

Anda dapat menambahkan middleware untuk validasi dan keamanan. Berikut adalah contoh validasi sederhana:


// Middleware for validating task data
const validateTask = (req, res, next) => {
  const { title } = req.body;
  if (!title) {
    return res.status(400).json({ message: 'Title is required' });
  }
  next();
};

// Use the middleware before the POST route
app.post('/tasks', validateTask, async (req, res) => {
  // ...
});

Middleware `validateTask` memeriksa apakah properti `title` ada di body permintaan. Jika tidak, ia mengembalikan respons kesalahan. Kita menggunakannya sebelum endpoint POST untuk memastikan bahwa semua tugas baru memiliki judul.

3.5. Uji Backend dengan Postman atau Insomnia

Setelah membuat endpoint API, uji dengan Postman atau Insomnia. Ini memungkinkan Anda mengirim permintaan HTTP ke backend Anda dan memverifikasi bahwa endpoint tersebut berfungsi seperti yang diharapkan.

Berikut adalah contoh permintaan POST untuk membuat tugas baru:

  • Method: POST
  • URL: http://localhost:5000/tasks
  • Headers: Content-Type: application/json
  • Body:
    
    {
      "title": "Learn React",
      "description": "Complete the React tutorial",
      "completed": false
    }
    

Pastikan server backend Anda berjalan saat Anda melakukan pengujian.

4. Membangun Frontend dengan React

Sekarang, mari kita bangun frontend kita dengan React. Kita akan membuat komponen untuk menampilkan daftar tugas, membuat formulir untuk membuat dan memperbarui tugas, dan menangani permintaan API.

4.1. Membuat Komponen React

Di dalam direktori `frontend`, buat direktori bernama `components`. Di dalam direktori `components`, buat file berikut:

  • TaskList.js
  • TaskForm.js

4.2. Menggunakan `useState` dan `useEffect` untuk Manajemen State dan Efek Samping

`useState` adalah hook yang memungkinkan Anda menambahkan state ke komponen fungsional. `useEffect` adalah hook yang memungkinkan Anda melakukan efek samping dalam komponen fungsional (misalnya, mengambil data dari API).

Di dalam `src/App.js`, tambahkan kode berikut:


import React, { useState, useEffect } from 'react';
import TaskList from './components/TaskList';
import TaskForm from './components/TaskForm';

function App() {
  const [tasks, setTasks] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchTasks = async () => {
      try {
        const response = await fetch('http://localhost:5000/tasks');
        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }
        const data = await response.json();
        setTasks(data);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchTasks();
  }, []); // Empty dependency array means this effect runs only once on mount

  const handleAddTask = async (newTask) => {
    try {
      const response = await fetch('http://localhost:5000/tasks', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(newTask),
      });

      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`);
      }

      const savedTask = await response.json();
      setTasks([...tasks, savedTask]); // Update state with the new task
    } catch (err) {
      setError(err);
      console.error("Error adding task:", err); // Log the error for debugging
    }
  };

  const handleDeleteTask = async (taskId) => {
    try {
      const response = await fetch(`http://localhost:5000/tasks/${taskId}`, {
        method: 'DELETE',
      });

      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`);
      }

      setTasks(tasks.filter(task => task._id !== taskId)); // Update state to remove the deleted task
    } catch (err) {
      setError(err);
      console.error("Error deleting task:", err); // Log the error for debugging
    }
  };


  if (loading) {
    return 

Loading tasks...

; } if (error) { return

Error: {error.message}

; } return ( <div> <h1>Task Manager</h1> <TaskForm onAddTask={handleAddTask} /> <TaskList tasks={tasks} onDeleteTask={handleDeleteTask} /> </div> ); } export default App;

Kode ini melakukan hal berikut:

  • Mengimpor hook `useState` dan `useEffect`.
  • Membuat state `tasks` untuk menyimpan daftar tugas, `loading` untuk menunjukkan apakah data sedang dimuat, dan `error` untuk menyimpan kesalahan apa pun.
  • Menggunakan `useEffect` untuk mengambil tugas dari backend saat komponen dipasang.
  • Menangani kesalahan dan menampilkan pesan kesalahan jika terjadi kesalahan.
  • Melewatkan daftar tugas dan fungsi `handleDeleteTask` ke komponen `TaskList`.
  • Melewatkan fungsi `handleAddTask` ke komponen `TaskForm`.

4.3. Mengambil Data dari Backend (Menggunakan `fetch` atau Axios)

Kita menggunakan `fetch` dalam kode di atas untuk mengambil data dari backend. Axios adalah alternatif populer yang menyediakan API yang lebih fleksibel. Untuk menggunakan Axios, instal dengan perintah:

npm install axios

Kemudian, ganti kode `fetch` dengan Axios:


import axios from 'axios';

// ...

useEffect(() => {
  const fetchTasks = async () => {
    try {
      const response = await axios.get('http://localhost:5000/tasks');
      setTasks(response.data);
    } catch (err) {
      setError(err);
    } finally {
      setLoading(false);
    }
  };

  fetchTasks();
}, []);

4.4. Menampilkan Data dalam Daftar

Di dalam `TaskList.js`, tambahkan kode berikut:


import React from 'react';

function TaskList({ tasks, onDeleteTask }) {
  return (
    <ul>
      {tasks.map(task => (
        <li key={task._id}>
          <strong>{task.title}</strong> - {task.description}
          <button onClick={() => onDeleteTask(task._id)}>Delete</button>
        </li>
      ))}
    </ul>
  );
}

export default TaskList;

Komponen ini menerima daftar tugas sebagai prop dan menampilkan setiap tugas dalam daftar. Ini juga mencakup tombol “Delete” yang memanggil fungsi `onDeleteTask` saat diklik.

4.5. Membuat Formulir untuk Membuat dan Memperbarui Data

Di dalam `TaskForm.js`, tambahkan kode berikut:


import React, { useState } from 'react';

function TaskForm({ onAddTask }) {
  const [title, setTitle] = useState('');
  const [description, setDescription] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();

    if (!title) {
      alert("Title is required");
      return;
    }

    const newTask = {
      title: title,
      description: description,
      completed: false
    };

    onAddTask(newTask);
    setTitle('');
    setDescription('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Title:
        <input
          type="text"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
        />
      </label>
      <br />
      <label>
        Description:
        <textarea
          value={description}
          onChange={(e) => setDescription(e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Add Task</button>
    </form>
  );
}

export default TaskForm;

Komponen ini membuat formulir untuk menambahkan tugas baru. Ia menggunakan state untuk menyimpan nilai input dan fungsi `handleSubmit` untuk mengirimkan data ke backend.

4.6. Menangani Pengiriman Formulir dan Pembaruan State

Kode di atas sudah menangani pengiriman formulir dan pembaruan state. Fungsi `handleSubmit` mencegah perilaku default formulir, membuat objek tugas baru, mengirimkannya ke backend, dan memperbarui state dengan tugas baru.

4.7. Menambahkan Fungsionalitas Delete

Fungsi `handleDeleteTask` di `App.js` dan tombol “Delete” di `TaskList.js` menangani fungsionalitas delete. Saat tombol “Delete” diklik, fungsi `handleDeleteTask` dipanggil dengan ID tugas, yang mengirimkan permintaan DELETE ke backend dan memperbarui state untuk menghapus tugas dari daftar.

4.8. Penanganan Error dan Umpan Balik Pengguna

Kode di atas menyertakan penanganan error dasar. Fungsi `useEffect` dan `handleAddTask` menyertakan blok `try…catch` untuk menangkap kesalahan apa pun yang terjadi saat mengambil atau membuat tugas. Pesan kesalahan ditampilkan kepada pengguna.

5. Menghubungkan Frontend dan Backend

Sekarang, mari kita pastikan frontend dan backend berkomunikasi dengan benar.

5.1. Mengkonfigurasi Permintaan CORS

CORS (Cross-Origin Resource Sharing) adalah mekanisme keamanan browser yang membatasi permintaan lintas asal. Kita telah menginstal dan menggunakan middleware `cors` di backend untuk mengaktifkan permintaan lintas asal dari frontend kita.

5.2. Memastikan Komunikasi yang Benar Antara Frontend dan Backend

Pastikan bahwa frontend Anda mengirimkan permintaan ke URL backend yang benar (misalnya, `http://localhost:5000/tasks`). Pastikan juga bahwa backend Anda berjalan dan mendengarkan port yang benar.

6. Peningkatan Lebih Lanjut dan Pertimbangan Desain

Berikut adalah beberapa peningkatan lebih lanjut dan pertimbangan desain untuk aplikasi CRUD Anda:

6.1. Validasi Input yang Lebih Baik

Tambahkan validasi input yang lebih baik di frontend dan backend untuk memastikan bahwa data yang dimasukkan valid. Anda dapat menggunakan library validasi seperti Yup atau Joi.

6.2. Pagination untuk Daftar Panjang

Jika Anda memiliki daftar tugas yang panjang, tambahkan pagination untuk membagi daftar menjadi halaman yang lebih kecil. Ini akan meningkatkan kinerja dan pengalaman pengguna.

6.3. Styling dengan CSS atau Library UI (Misalnya, Material UI, Bootstrap)

Tambahkan styling ke aplikasi Anda menggunakan CSS atau library UI seperti Material UI atau Bootstrap. Ini akan membuat aplikasi Anda terlihat lebih menarik dan ramah pengguna.

6.4. Autentikasi dan Otorisasi

Tambahkan autentikasi dan otorisasi untuk mengamankan aplikasi Anda. Ini akan memastikan bahwa hanya pengguna yang berwenang yang dapat mengakses dan memodifikasi data.

6.5. Penerapan (Deployment) Aplikasi

Sebarkan aplikasi Anda ke server produksi agar dapat diakses oleh orang lain. Ada banyak platform yang tersedia untuk penerapan, seperti Netlify, Vercel, dan Heroku.

7. Kesimpulan: Refleksi dan Langkah Selanjutnya

Selamat! Anda telah berhasil membangun aplikasi CRUD dengan React dan Node.js. Proyek ini adalah fondasi yang bagus untuk membangun aplikasi web yang lebih kompleks. Teruslah berlatih dan bereksperimen dengan teknologi baru untuk meningkatkan keterampilan full-stack development Anda.

Langkah selanjutnya meliputi:

  • Membangun aplikasi yang lebih kompleks dengan fitur tambahan.
  • Mempelajari tentang database lain, seperti PostgreSQL atau MySQL.
  • Mempelajari tentang teknologi backend lainnya, seperti Django atau Ruby on Rails.
  • Mempelajari tentang alat dan teknik pengujian.
  • Membangun portofolio proyek untuk menunjukkan keterampilan Anda kepada calon pemberi kerja.

Semoga perjalanan 200 hari full-stack development ini terus menginspirasi Anda. Teruslah belajar dan membangun!

“`

omcoding

Leave a Reply

Your email address will not be published. Required fields are marked *