Proyek ini menghimpun materi dari beberapa section sebelumnya menjadi satu layanan yang utuh: REST API untuk manajemen tugas, tempat client dapat membuat, membaca, mengubah, dan menghapus tugas lewat HTTP. Kita membangunnya tanpa framework — cukup module node:http bawaan Node.js — karena tujuan proyek ini adalah memahami routing, parsing body, status code, dan penyimpanan data dari lapisan paling bawah. Data disimpan pada berkas JSON sehingga proyek berjalan tanpa database terpisah, dan seluruh perilakunya diverifikasi test otomatis yang kita tulis bersama kodenya. Proyek ini menerapkan langsung pola dari Section HTTP dan Web Servers, REST API, Filesystem, serta Testing.

Yang Kita Bangun #

Resource utama API ini adalah tugas dengan tiga field: id (angka), judul (teks 3-80 karakter setelah dipangkas), dan status (salah satu dari todo, doing, atau done). Status baru selalu dimulai dari todo bila client tidak mengirimnya. Berikut seluruh endpoint yang kita sediakan:

MethodURLAksiSuksesGalat
GET/tugasDaftar tugas, bisa disaring dengan ?status=200—
POST/tugasBuat tugas baru201 + header Location400, 422
GET/tugas/{id}Detail satu tugas200404
PUT/tugas/{id}Ganti seluruh isi tugas200400, 404, 422
PATCH/tugas/{id}Ubah sebagian field tugas200400, 404, 422
DELETE/tugas/{id}Hapus tugas204 tanpa body404

Pemisahan kode galat mengikuti disiplin Section REST API: 400 berarti body tidak bisa dibaca sebagai JSON, 422 berarti body terbaca tetapi isinya tidak lolos validasi, 404 berarti resource atau endpoint tidak ada, dan 405 berarti method tidak didukung pada endpoint tersebut. Semua galat memakai satu bentuk response agar client cukup menulis satu kode parsing:

json Bentuk error seragam
{
  "error": {
    "kode": "TIDAK_ADA",
    "pesan": "Tugas 99 tidak ditemukan"
  }
}

Field kode bersifat stabil untuk dibaca mesin; field pesan bebas untuk dibaca manusia; field detail opsional dan berisi daftar galat validasi per field.

Struktur Direktori #

Kode proyek terbagi rapi per tanggung jawab agar setiap berkas mudah dibaca dan diuji:

text Struktur direktori proyek
rest-api-manajemen-tugas/
├── package.json          # type module — semua berkas .js adalah ESM
├── data/
│   └── tugas.json        # dibuat otomatis saat penulisan pertama
├── src/
│   ├── json.js           # helper baca body dan kirim response JSON
│   ├── server.js         # server HTTP, tabel rute, error terpusat
│   ├── tugas.js          # validasi, penyimpanan di memori, handler
│   ├── penyimpanan.js    # penyimpanan berbasis berkas JSON
│   ├── cli.js            # titik masuk produksi (port dari PORT)
│   ├── demo-routing.js   # sesi demo routing
│   ├── demo.js           # sesi demo CRUD lengkap
│   └── demo-simpan.js    # sesi demo persistensi
└── tests/
    ├── tugas.test.js     # unit test validasi dan penyimpanan memori
    ├── penyimpanan.test.js
    └── integrasi.test.js # integration test lewat HTTP sungguhan

Perilaku yang Diharapkan #

Cara termudah melihat perilaku API adalah menjalankan sesi demo yang sudah disertakan — satu proses yang menyalakan server pada port ephemeral, mengirim rangkaian permintaan, lalu menutup server dengan rapi:

bash
node src/demo.js

Output yang Dihasilkan:

text
GET /tugas -> 200 [{"id":1,"judul":"Menulis dokumentasi API","status":"doing"},{"id":2,"judul":"Menyiapkan rapat mingguan","status":"todo"}]
POST /tugas -> 201 (lokasi: /tugas/3) {"id":3,"judul":"Meninjau pull request","status":"todo"}
GET /tugas?status=todo -> 200 [{"id":2,"judul":"Menyiapkan rapat mingguan","status":"todo"},{"id":3,"judul":"Meninjau pull request","status":"todo"}]
GET /tugas/1 -> 200 {"id":1,"judul":"Menulis dokumentasi API","status":"doing"}
PATCH /tugas/3 -> 200 {"id":3,"judul":"Meninjau pull request","status":"doing"}
PUT /tugas/1 -> 200 {"id":1,"judul":"Menulis dokumentasi API v2","status":"todo"}
DELETE /tugas/2 -> 204 (body kosong)
GET /tugas/2 -> 404 {"error":{"kode":"TIDAK_ADA","pesan":"Tugas 2 tidak ditemukan"}}
POST /tugas (judul terlalu pendek) -> 422 {"error":{"kode":"VALIDASI_GAGAL","pesan":"Data tugas tidak lolos validasi","detail":[{"field":"judul","pesan":"judul harus 3-80 karakter setelah dipangkas"}]}}
POST /tugas (body bukan JSON) -> 400 {"error":{"kode":"JSON_TIDAK_VALID","pesan":"Body permintaan bukan JSON valid"}}
PATCH /tugas/99 -> 404 {"error":{"kode":"TIDAK_ADA","pesan":"Tugas 99 tidak ditemukan"}}
DELETE /tugas -> 405 {"error":{"kode":"METODE_TIDAK_DIIZINKAN","pesan":"Metode DELETE tidak didukung pada endpoint ini"}}

Bacaan singkat output di atas: POST menjawab 201 beserta lokasi resource baru, query ?status=todo menyaring koleksi, PUT mengganti seluruh isi sementara PATCH hanya menyentuh field yang dikirim, DELETE menjawab 204 tanpa body, dan empat baris terakhir memperlihatkan galat validasi 422, body non-JSON 400, resource tiada 404, serta method asing 405.

Untuk pemakaian sungguhan, server dinyalakan lewat titik masuk produksi lalu dihubungi dengan client HTTP apa pun:

bash
PORT=3000 node src/cli.js
bash
curl 127.0.0.1:3000/tugas
curl -X POST 127.0.0.1:3000/tugas -H 'Content-Type: application/json' -d '{"judul": "Belajar Node.js"}'

Server berjalan sampai dihentikan dengan Ctrl+C, dan data tersimpan di data/tugas.json sehingga tetap ada pada pemakaian berikutnya. Seluruh suite test dijalankan dengan node --test dari akar proyek.

Pembagian Empat Bagian #

Pembangunan proyek ini mengikuti empat tahap yang berdiri di atas tahap sebelumnya:

  1. Bagian 1 — Server dan Routing: membangun src/json.js dan src/server.js — helper JSON, tabel rute, pembedaan 404/405, dan penanganan error terpusat yang menjawab 500.
  2. Bagian 2 — CRUD Tugas: mengisi logika bisnis pada src/tugas.js — kontrak penyimpanan, validasi input, serta handler untuk kelima operasi endpoint dengan status code yang tepat.
  3. Bagian 3 — Penyimpanan JSON: memindahkan data ke src/penyimpanan.js — berkas data/tugas.json, id deterministik dari id terbesar, dan penulisan atomik lewat berkas sementara.
  4. Bagian 4 — Pengujian API: mengunci perilaku dengan node --test — unit test untuk domain dan penyimpanan, integration test dengan server nyata pada port ephemeral, lalu perapihan titik masuk produksi.

Setiap bagian menutup satu keputusan arsitektur: bagian 1 memisahkan lapisan HTTP dari logika, bagian 2 memisahkan logika dari penyimpanan lewat kontrak method, bagian 3 menukar implementasi penyimpanan tanpa menyentuh handler, dan bagian 4 membuktikan semuanya bekerja dari luar sebagaimana client melihatnya. Mari kita mulai dari fondasinya.