Proyek ini adalah RESTful API sederhana untuk mengelola koleksi buku, dibangun dengan Node.js (CommonJS) dan Hapi.
API memenuhi kriteria wajib Bookshelf API (Dicoding): port 9000, runner npm run start, penyimpanan in-memory (tanpa DB/JSON), serta seluruh endpoint CRUD berikut validasi dan format respons sesuai spesifikasi.
- Kriteria 1 – Port 9000
Server lokal berjalan pada
http://localhost:9000. - Kriteria 2 – Runner
Jalankan dengan
npm run start(bukan nodemon). - Kriteria 3 – Tambah Buku (
POST /books) Validasinamewajib, danreadPage <= pageCount. Server mengisiid,finished,insertedAt,updatedAt. - Kriteria 4 – Daftar Buku (
GET /books) Kembalikan hanyaid,name,publisher. Opsional+: dukung query?name,?reading=0|1,?finished=0|1. - Kriteria 5 – Detail Buku (
GET /books/{bookId}) - Kriteria 6 – Perbarui Buku (
PUT /books/{bookId}) Validasinamewajib,readPage <= pageCount. - Kriteria 7 – Hapus Buku (
DELETE /books/{bookId})
Semua pesan dan status code disesuaikan dengan yang diminta oleh pengujian otomatis.
bookshelf-api/
├─ package.json
└─ src/
├─ server.js // bootstrap Hapi (port 9000, npm run start)
├─ routes.js // definisi route
├─ handlers.js // handler tiap endpoint + validasi
└─ books.js // penyimpanan in-memory (array)
- Node.js (LTS ≥ 18.13.0)
- @hapi/hapi – HTTP server & routing
- nanoid@3 – generator
idunik - (Opsional) ESLint – konsistensi gaya kode
- Clone & install
git clone https://github.com/zidanindratama/submission-07-bookshelf-api
cd submission-07-bookshelf-api
npm install- Start server (wajib untuk submission)
npm run start
# Server: http://localhost:9000Pastikan tidak menjalankan dengan
nodemonsaat submit. Jika perlu untuk dev, gunakan script terpisahstart-dev.
Body (JSON):
{
"name": "Buku A",
"year": 2010,
"author": "John Doe",
"summary": "Lorem ipsum",
"publisher": "Dicoding Indonesia",
"pageCount": 100,
"readPage": 25,
"reading": false
}201 (success):
{
"status": "success",
"message": "Buku berhasil ditambahkan",
"data": { "bookId": "Qbax5Oy7L8WKf74l" }
}400 (tanpa name):
{ "status": "fail", "message": "Gagal menambahkan buku. Mohon isi nama buku" }400 (readPage > pageCount):
{
"status": "fail",
"message": "Gagal menambahkan buku. readPage tidak boleh lebih besar dari pageCount"
}200:
{
"status": "success",
"data": {
"books": [
{ "id": "Qbax5...", "name": "Buku A", "publisher": "Dicoding Indonesia" }
]
}
}Opsional – Query:
?name=teks→ filter nama (case-insensitive)?reading=0|1→false|true?finished=0|1→false|true
200:
{
"status": "success",
"data": {
"book": {
"id": "aWZB...",
"name": "Buku A",
"year": 2010,
"author": "John Doe",
"summary": "Lorem ipsum",
"publisher": "Dicoding Indonesia",
"pageCount": 100,
"readPage": 25,
"finished": false,
"reading": false,
"insertedAt": "2021-03-04T09:11:44.598Z",
"updatedAt": "2021-03-04T09:11:44.598Z"
}
}
}404 (tidak ditemukan):
{ "status": "fail", "message": "Buku tidak ditemukan" }Body (JSON): sama seperti POST /books.
200:
{ "status": "success", "message": "Buku berhasil diperbarui" }400 (tanpa name):
{ "status": "fail", "message": "Gagal memperbarui buku. Mohon isi nama buku" }400 (readPage > pageCount):
{
"status": "fail",
"message": "Gagal memperbarui buku. readPage tidak boleh lebih besar dari pageCount"
}404 (id tidak ditemukan):
{ "status": "fail", "message": "Gagal memperbarui buku. Id tidak ditemukan" }200:
{ "status": "success", "message": "Buku berhasil dihapus" }404 (id tidak ditemukan):
{ "status": "fail", "message": "Buku gagal dihapus. Id tidak ditemukan" }