CRUD API dengan Express — Node.js

Mari bangun REST API lengkap untuk mengelola data todo. Full CRUD API: import express from "express"; const app = express(); app.use(express.json()); let…

CRUD adalah empat hal yang dilakukan hampir semua aplikasi ke datanya: Create (bikin), Read (baca), Update (ubah), Delete (hapus). Bayangin buku catatan di mejamu: kamu menulis halaman baru, membaca halaman lama, mencoret lalu menulis ulang, dan menyobek halaman yang gak perlu. API catatan kita melakukan empat hal yang sama, lewat empat method HTTP: POST, GET, PUT, dan DELETE.

🧪 Tebakan cepat: catatan 1 baru saja dihapus, jadi isinya tinggal catatan id 2 dan 3. Lalu kamu POST catatan baru, dan id-nya dihitung dengan catatan.length + 1. Id berapa yang didapat catatan baru itu? Tebak dulu, jawabannya ada di bagian "Create: id dari nextId, bukan dari panjang array".

Empat huruf, lima route

Huruf Method dan path Kalau berhasil Kalau id-nya gak ada
Create POST /catatan 201 Created + catatan baru
Read GET /catatan 200 OK + semua catatan
Read GET /catatan/:id 200 OK + satu catatan 404 Not Found
Update PUT /catatan/:id 200 OK + catatan yang sudah diubah 404 Not Found
Delete DELETE /catatan/:id 204 No Content, tanpa body 404 Not Found

Satu lagi yang akan sering kamu pakai: 400 Bad Request, untuk data kiriman yang salah atau kurang. Itu bahan pelajaran Validasi.

Kode lengkapnya

const express = require("express");
const app = express();
app.use(express.json());

const catatan = [
  { id: 1, judul: "Belanja", isi: "beli beras 5 kg" },
  { id: 2, judul: "Belajar", isi: "bab Node.js" },
];
let nextId = 3;

// Read: semua catatan
app.get("/catatan", (req, res) => {
  res.json(catatan);
});

// Read: satu catatan
app.get("/catatan/:id", (req, res) => {
  const item = catatan.find((c) => c.id === Number(req.params.id));
  if (!item) return res.status(404).json({ error: "Catatan tidak ditemukan" });
  res.json(item);
});

// Create
app.post("/catatan", (req, res) => {
  const { judul, isi } = req.body;
  const baru = { id: nextId++, judul, isi };
  catatan.push(baru);
  res.status(201).json(baru);
});

// Update
app.put("/catatan/:id", (req, res) => {
  const item = catatan.find((c) => c.id === Number(req.params.id));
  if (!item) return res.status(404).json({ error: "Catatan tidak ditemukan" });
  item.judul = req.body.judul;
  item.isi = req.body.isi;
  res.json(item);
});

// Delete
app.delete("/catatan/:id", (req, res) => {
  const index = catatan.findIndex((c) => c.id === Number(req.params.id));
  if (index === -1) return res.status(404).json({ error: "Catatan tidak ditemukan" });
  catatan.splice(index, 1);
  res.status(204).end();
});

app.listen(3000, () => {
  console.log("Server jalan di http://localhost:3000");
});

Create: id dari nextId, bukan dari panjang array

Di pelajaran Express Dasar, id baru dihitung dengan catatan.length + 1. Itu benar selama gak ada yang dihapus. Coba urutan ini:

Langkah Isi array sesudahnya length + 1 memberi nextId++ memberi
awal 1, 2
POST Olahraga 1, 2, 3 3 3
DELETE /catatan/1 2, 3
POST Masak 2, 3, ? 3 (dobel!) 4

Array tinggal dua catatan, jadi length + 1 = 3, padahal id 3 sudah dipakai Olahraga. Jawabannya 3, dan sekarang ada dua catatan ber-id 3. Itu jawaban tebakannya. GET /catatan/3 selalu menemukan yang pertama, dan yang kedua gak bisa diambil. Penghitung nextId cuma naik, gak pernah turun, jadi id-nya gak pernah dipakai dua kali.

Update: PUT mengganti seluruh catatan

PUT artinya "ganti catatan ini dengan yang kukirim". Kirim lengkap, judul dan isi:

curl -X PUT http://localhost:3000/catatan/2 -H "Content-Type: application/json" -d '{"judul":"Belajar Express"}'
{"id":2,"judul":"Belajar Express"}

Body-nya cuma berisi judul, jadi req.body.isi adalah undefined, dan isi lama ikut hilang (JSON gak menulis nilai undefined). Untuk mengubah sebagian saja, API biasanya menyediakan PATCH, yang menimpa field yang dikirim saja. Kita belum punya route PATCH, jadi Express menjawab Cannot PATCH /catatan/2.

Delete: 204 No Content

curl -i -X DELETE http://localhost:3000/catatan/1 mencetak HTTP/1.1 204 No Content, beberapa header, lalu selesai: gak ada body. 204 artinya "berhasil, dan gak ada isi yang dikirim balik", dan res.status(204).end() mengakhiri jawaban tanpa body. Hapus /catatan/1 sekali lagi dan jawabannya 404 {"error":"Catatan tidak ditemukan"}, karena catatannya sudah gak ada.

📌 Express 5: body tanpa Content-Type

curl -d '{"judul":"Olahraga"}' tanpa -H "Content-Type: application/json" mengirim body sebagai data form, jadi express.json() melewatinya. Di Express 5, req.body tetap undefined, dan const { judul, isi } = req.body berakhir dengan 500: TypeError: Cannot destructure property 'judul' of 'req.body' as it is undefined. Express 4 mengisi req.body dengan {}, dan diam-diam menyimpan catatan tanpa judul dan isi, seperti {"id":3}.

Di latihan: CRUD tanpa server

Latihannya memakai array books dan dua fungsi. listBooks() sudah ada. Kamu mengisi addBook(title, author): buat object { id: nextId++, title, author }, push ke books, lalu return object itu. Kode awal yang memanggilnya mencetak:

Daftar awal: 1 buku
Buku ditambah: {"id":2,"title":"Bumi","author":"Tere Liye"}
Buku ditambah: {"id":3,"title":"Pulang","author":"Leila S. Chudori"}
Setelah tambah: 3 buku

⚠️ Jebakan yang sering ketemu

TL;DR: CRUD = Create, Read, Update, Delete = POST /catatan (201), GET /catatan dan GET /catatan/:id (200), PUT /catatan/:id (200), DELETE /catatan/:id (204). Id yang gak ada dijawab 404 dengan return res.status(404).json(...). Pasang express.json() supaya req.body terisi. Id baru dari penghitung nextId++, bukan catatan.length + 1 yang bisa dobel setelah DELETE. PUT mengganti seluruh catatan, PATCH cuma sebagian. res.status(204).end() menjawab berhasil tanpa body, res.json() mengirim data, res.status(201) mengatur status-nya.

Yang akan kamu pelajari