Hi Co.Creators! Pada artikel sebelumnya, kita sudah mempelajari cara bikin project API baru menggunakan Node.js, juga mempersiapkan library yang dibutuhkan dalam project tersebut. Kita sudah membuat endpoint-endpoint baru yang sudah dites dengan aplikasi Postman dan mendapatkan hasil yang masih berupa dummy.
Dalam bagian ini, kita akan membuat API tersebut jadi lebih berguna. Kamu bakal belajar cara melakukan beberapa operasi pada MongoDB seperti create, read, update, dan delete. Setelah bisa, kamu juga bakal belajar mengintegrasikannya dengan API yang sudah dibuat pada artikel sebelumnya. Jangan khawatir bakal kesulitan atau gagal saat menjalankannya, soalnya aku bakal membagikan source code untuk tutorial ini di GitHub sama kayak artikel sebelumnya.
Persiapan
MongoDB
Dikutip dari Wikipedia, MongoDB adalah sistem basis data berorIentasi dokumen lintas platform. Diklasifikasikan sebagai basis data “NoSQL”, MongoDB menghindari struktur basis data relasional tabel berbasis tradisional yang mendukung JSON seperti dokumen dengan skema dinamis (MongoDB menyebutnya sebagai format BSON), membuat integrasi data dalam beberapa jenis aplikasi lebih mudah dan lebih cepat. Kamu bisa melihat cara melakukan instalasi MongoDB melalui tautan berikut.
MongoDB GUI
Kalau lebih suka mengakses database dengan GUI, kamu bisa download di NoSQL Booster atau Robo3T.
Project dari Bagian I
Apabila kamu mau memulai dari baru, kamu bisa clone dari repository ini.
Instalasi Library MongoDB
Buka Terminal dan jalankan npm i mongodb di direktori project. Kamu akan melihat hasilnya seperti berikut.
Pastikan MongoDB Berfungsi Dengan Baik
Jalankan mongo pada Terminal. Seharusnya MongoDB sudah berfungsi dengan baik kalau kamu melihat hasil seperti gambar berikut.
Kamu bisa mencoba memasukkan query MongoDB untuk melakukan perubahan database di Terminal ini. Aku sendiri sih lebih suka menggunakan NoSQL Booster untuk melakukan query data di MongoDB.
Bagian 2 – Read, Insert, Update, Delete Data dengan MongoDB
Membuat Koneksi dengan MongoDB
Kita akan membuat script mongoDbConnector.js. Di sini kita akan menambahkan code yang terkait MongoDB.
Membuat Modul Konektor MongoDB
Pertama-tama kamu harus terkoneksi dengan service MongoDB supaya bisa menggunakan semua fitur yang telah disediakan. Lihat bagian code mongoDbConnector.js berikut ini.
// mongoDbConnector.js const mongodb = require(‘mongodb’); class MongoDbConnector { constructor(config){ Object.assign(this, { config }); } connect(){ const { host, name } = this.config; const options = { useUnifiedTopology: true, useNewUrlParser: true }; mongodb.MongoClient.connect(host, options, (err, client) => { if (err) { console.log(err); } else { console.log(“Connected successfully to DB”); const db = client.db(name); Object.assign(this, { db, client }); } }); } disconnect(){ this.client.close(); console.log(“Disconnected DB successfully!”); } } module.exports = MongoDbConnector; |
Langkah pertama adalah membuat sebuah class bernama MongoDbConnector, yang berisikan semua operasi MongoDB yang ditentukan nantinya. Kemudian, buat 2 public function connect() dan disconnect(). Fungsi connect() digunakan untuk memulai koneksi ke MongoDB saat API server ini dijalankan pertama kali. Sementara disconnect() akan dieksekusi ketika server di-kill.
Di fungsi connect(), kita panggil fungsi MongoClient.connect() dari library mongodb yang telah diinstal sebelumnya pada project. Fungsi MongoClient.connect() membutuhkan beberapa argument yaitu host, options, dan sebuah fungsi callback. Fungsi callback ini akan memanggil client.db(name) untuk terhubung dengan database yang diinginkan apabila koneksi sudah berhasil. Terakhir, kita akan memasukkan db dan client sebagai property dari object MongoDbConnector.
Lalu fungsi dari disconnect() adalah dengan menjalankan fungsi this.client.close(), koneksi yang sudah terhubung dengan MongoDB akan diputuskan. Yang paling terakhir, lakukan export pada class ini dengan menggunakan module.exports, karena class ini akan digunakan di index.js.
Import MongoDbConnector
Mari kita kembali ke index.js. Di file ini, kita akan melakukan import untuk membuat object dari class MongoDbConnector. Lihatlah potongan kode berikut.
// index.js … const port = 3000; const MongoDbConnector = require(‘./mongoDbConnector’); const mongoDbConnector = new MongoDbConnector({ name: ‘cil-rest-api’, host: ‘mongodb://localhost:27017’ }); mongoDbConnector.connect(); app.use(bodyParser.json()); app.post(‘/user’, (req, res) => { … }); … app.listen(port, () => {…}); [‘SIGINT’, ‘SIGTERM’].forEach((signal) => { process.on(signal, async () => { console.log(“Stop signal received”); mongoDbConnector.disconnect(); console.log(“Exiting now, bye!”); process.exit(0); }); }); |
Pertama, kita import class dengan require(‘./mongoDbConnector’). Kemudian buatlah sebuah object MongoDbConnector dengan sebuah argument yang berisi konfigurasi koneksi. Untuk saat ini, yang dibutuhkan barulah name dan host. Kemudian tambahkan mongoDbConnector.connect() untuk terhubung dengan server MongoDB.
mongoDbConnector.disconnect() akan dipanggil saat API server ini dimatikan dengan SIGINT atau SIGTERM. Sebelum process.exit(0) dijalankan, semua koneksi harus diputuskan terlebih dahulu.
Lakukan Code Testing
Jalankan npm start di Terminal. Apabila semua langkah di atas sudah dilakukan dengan benar, seharusnya kamu akan melihat hasilnya seperti gambar di bawah ini.
Membuat User Baru
Sekarang, kita akan menambahkan modul untuk membuat user baru dengan cara memasukkan data user tersebut ke dalam MongoDB.
MongoDB Connector
Pertama, buka kembali mongoDbConnector.js, tambahkan seperti yang ada pada potongan kode berikut.
// mongoDbConnector.js … class MongoDbConnector { … disconnect() { … } async insertOne(collection, data){ try { const res = await this.db.collection(collection).insertOne(data); const textRes = res.result.ok ? `Success insert data to collection ${collection}!`: `Failed insert data to collection ${collection}!`; console.log(textRes); return textRes; } catch(err) { throw err; } } } |
Fungsi insertOne() dibuat sebagai fungsi asynchronous, karena diperlukan beberapa waktu biar hasil eksekusi dari fungsi ini bisa didapatkan dari service lainnya (dalam hal ini MongoDB). Fungsi ini membutuhkan 2 parameter collection dan data. Kalau kamu lebih memahami RDBMS seperti MySQL, maka collection ini memiliki peran yang serupa dengan table. Perhatikan juga bahwa kamu gak perlu mendefinisikan nama collection baru saat memasukkan data pertama, karena MongoDB akan otomatis membuat collection baru kalau belum ada.
Operasi insertOne() ini sangat bergantung dengan availability dari MongoDB yang terkoneksi. Dengan demikian, sangat disarankan untuk menggunakan try-catch untuk logika yang diterapkan. Di dalam try block, fungsi untuk memasukkan data akan dipanggil oleh this.db.collection(collection).insertOne(data);. Apabila data berhasil dimasukkan, fungsi ini akan mengembalikan teks yang menandakan sukses. Apabila gagal, teks gagal akan dimunculkan. Lalu, di dalam catch block, sebuah error akan di-throw apabila terjadi kegagalan dalam memasukkan data ke dalam MongoDB.
Index.js
Berikutnya, kita akan memodifikasi endpoint POST /user yang telah dibuat sebelumnya, supaya endpoint ini dapat memasukkan data request ke dalam database. Lihatlah potongan kode berikut.
// index.js … const collection = ‘cil-users’; … app.post(‘/user’, async (req, res) => { const result = await mongoDbConnector.insertOne(collection, req.body); res.send(result); }); … |
Pertama, definisikan nama collection dahulu supaya collection yang dipakai tetap konsisten dan gak dibuat berulang-ulang saat membuat fungsi lain yang memerlukan collection yang sama.
Kemudian, ubah app.post(‘/user’). Tambahkan async pada fungsi callback tersebut, dan masukkan fungsi await mongoDbConnector.insert() dengan argumen collection dan req.body. Ketika hasil sudah didapatkan dan disimpan dalam variabel result, kirimkan kembali sebagai respons dari endpoint ini menggunakan fungsi res.send().
Lakukan Code Testing
Buka Terminal dan jalankan npm start. Lakukan beberapa tes untuk memastikan semua sudah berjalan dengan benar pada POST /user. Hasilnya kira-kira seperti pada gambar di bawah ini.
Kemudian, bukalah aplikasi NoSQL Booster atau Robo 3T. Kamu harusnya melihat database “cil-rest-api” sudah terbuat dengan collection “cil-users” seperti gambar di bawah
Database “cil-rest-api” dengan collection “cil-users” berhasil dibuat!
Terakhir, lakukan cek apakah data benar-benar berhasil dimasukkan ke collection tersebut dengan command ini di NoSQL Booster:
Data yang berhasil dimasukkan dengan NoSQL Booster.
Mendapatkan User (Banyak)
Berikutnya kita akan membuat modul untuk mendapatkan user dalam jumlah banyak. Perubahan juga akan dilakukan di mongoDbConnector.js dan index.js.
MongoDB Connector
Di file ini, kita akan menambahkan fungsi baru bernama find(). Lihatlah potongan kode berikut.
// mongoDbConnector.js … class MongoDbConnector { … async find(collection, filter) { try { const res = await this.db.collection(collection).find(filter); return res.toArray(); } catch (err) { throw err; } } … } |
Pertama, buatlah fungsi find() yang membutuhkan 2 parameter: collection dan filter. Filter berisi query untuk mendapatkan data yang diinginkan dalam bentuk JSON, contohnya
{ username: ‘johndoe’ }
Berikutnya, buat sebuah block try-catch untuk mendeteksi terjadinya error. Di dalam block tersebut, sebuah fungsi db.collection().find() akan dipanggil. Fungsi ini akan mengembalikan sebuah list data dalam bentuk JSON yang memenuhi kriteria yang telah didefinisikan dalam filter. Dan list data tersebut akan disimpan dalam variabel res.
Terakhir, data dalam res akan dikonversi jadi sebuah array dengan fungsi .toArray(). Data ini akan dikembalikan sebagai hasil dari mengeksekusi MongoDbConnector.find().
index.js
Modul berikutnya yang akan diubah adalah index.js. Di sini kita akan mengintegerasikan fungsi find() dari MongoDbConnector ke endpoint GET /user. Berikut caranya.
// index.js … app.get(‘/user’, async (req, res) => { const result = await mongoDbConnector.find(collection, {}); res.send(result); }); … |
Implementasi dilakukan pada app.get(“/user”). Pertama, ubah callback function menjadi fungsi asynchronous dengan menambahkan async. Kemudian, tambahkan fungsi await mongoDbConnector.find() dengan argumen collection dan {}. Terakhir, kembalikan result melalui res.send() sebagai hasil dari memanggil endpoint ini.
Lakukan Testing Code
Jalankan kembali service ini dengan npm start. Lalu, buka aplikasi Postman atau Insomnia dan akses GET http://localhost:3000/user. Apabila penambahan modul ini berhasil dilakukan, kamu seharusnya melihat hasil seperti gambar berikut.
Contoh hasil menambahkan modul GET /user
Mendapatkan User (Satu)
Fungsi yang akan dibuat adalah findOne(). Perubahan juga akan dilakukan pada file mongoDbConnector.js dan index.js.
MongoDB Connector
Tambahkan findOne() pada file ini seperti pada potongan kode berikut.
// mongoDbConnector.js class MongoDbConnector { … async findOne(collection, filter) { try { const res = await this.db.collection(collection).findOne(filter); return res || ‘Data not found.’; } catch (err) { throw err; } } … } |
Fungsi findOne() juga merupakan fungsi asynchronous seperti fungsi lainnya, karena harus menunggu respons dari database setelah fungsi ini dieksekusi. Ada 2 parameter yang dibutuhkan fungsi findOne(), yaitu collection dan filter.
Seperti pada insert(), find() dan fungsi-fungsi lainnya yang membutuhkan respons dari external service, gunakan try-catch supaya error bisa di-handle dengan baik kalau terjadi. Di dalam block try, tambahkan fungsi db.collection().findOne() dengan masing-masing fungsi memiliki argumen collection dan filter. Hasil dari fungsi tersebut akan disimpan dalam res. Nilai dari res akan dikembalikan di akhir fungsi async findOne() apabila ada. Kalau gak ada, fungsi ini akan mengembalikan pesan “Data not found.”
index.js
Sama seperti insert() dan find() yang sudah dibuat sebelumnya, kita akan menambahkan findOne() di file index.js. Bagian yang akan ditambahkan adalah GET /user/:id. Potongan kode berikut adalah cara menambahkan fungsi findOne().
// index.js … const MongoDbConnector = require(‘./mongoDbConnector’); const { ObjectId } = require(‘mongodb’); … app.get(‘/user/:id’, async (req, res) => { const filter = { _id: ObjectId(req.params.id) }; const result = await mongoDbConnector.findOne(collection, filter); res.send(result); }); … |
Bagian kode yang akan diubah adalah app.get(‘/user/:id’). Pertama, buatlah fungsi callback dari fungsi app.get() ini menjadi fungsi asynchronous. Lalu tambahkan fungsi mongoDbConnector.findOne() dengan argumen collection dan filter.
Salah satu dari property pada filter adalah _id, yang akan digunakan untuk mendapatkan user spesifik yang dicari. Namun, _id dibuat oleh MongoDB secara otomatis untuk tiap data baru yang dimasukkan, dan harus dalam bentuk ObjectId. Dengan demikian, ObjectId harus di-import dari library mongodb di awal file index.js ini. Hasil apa pun yang didapatkan dari mongoDbConnector.findOne() akan dikembalikan sebagai response melalui res.send().
Lakukan Code Testing
Jalankan lagi service ini dengan npm start. Lalu, buka kembali aplikasi Postman dan cobalah akses GET http://localhost:3000/user/<_id>. Contoh _id bisa didapatkan di database. Apabila di database ada data yang memiliki _id tersebut, kamu akan melihat hasilnya seperti pada gambar berikut.
Apabila data gak ditemukan, kamu akan melihat hasilnya seperti gambar berikut.
Melakukan Update Data User
Sekarang, kita akan menambahkan modul untuk mengubah data user yang sudah ada sebelumnya.
MongoDB Connector
Fungsi yang akan ditambahkan di file mongoDbConnector.js adalah updateOne(). Caranya dapat dilihat di potongan kode berikut.
// mongoDbConnector.js class MongoDbConnector { … async updateOne(collection, filter, data) { try { const res = await this.db.collection(collection).updateOne(filter, { $set: data }); const { nModified, ok } = res.result; return nModified && ok ? ‘Successfully updated data’ : ‘Failed to update data’; } catch (err) { throw err; } } … } |
updateOne() memerlukan 3 parameter yaitu collection, filter, dan data. filter digunakan untuk memilih data mana yang mau diubah, dan data akan menambahkan atau mengubah property data yang didapatkan dari kriteria filter.
Dan seperti sebelumnya, kita akan menambahkan block try-catch. Di dalam block try tersebut, gunakan .updateOne(filter, { $set: data }); untuk menjalankan perubahan data di database. Hal yang perlu kamu perhatikan adalah argumen kedua membutuhkan $set supaya perubahan data bisa dilakukan. Untuk lebih detailnya, kamu bisa lihat dokumentasi ini.
Hasil yang didapatkan dari db.collection().updateOne() akan disimpan dalam res. Isi dari variabel res adalah result.nModified dan result.ok. Jika nilai dari nModified lebih besar dari 0 dan ok juga lebih besar dari 0, maka fungsi async updateOne() akan mengembalikan pesan sukses. Sebaliknya jika gagal, maka pesan gagal akan dimunculkan.
index.js
Kita akan mengaplikasikan updateOne() yang telah dibuat sebelumnya di index.js. Yang akan diubah dalam file ini adalah PATCH /user/:id, sebagaimana ditunjukkan dalam potongan kode berikut.
// index.js … app.patch(‘/user/:id’, async (req, res) => { const result = await mongoDbConnector.updateOne( collection, { _id: ObjectId(req.params.id) }, req.body ); res.send(result); }); … |
Perubahan dilakukan pada app.patch(‘/user/:id’). Pertama, tambahkan async pada fungsi callback pada app.patch(). Kemudian, tambahkan mongoDbConnector.updateOne() yang membutuhkan argumen collection, filter dengan id, dan data yang akan menjadi perubahan apabila data ditemukan pada database.
Pencarian menggunakan _id membutuhkan konversi dari string menjadi ObjectId pada MongoDB, sama seperti pada bagian mendapatkan satu user. Untuk argumen terakhir, data akan diisi req.body yang merupakan sebuah object.
Lakukan Code Testing
Jalankan npm start untuk memulai service. Kemudian buka aplikasi Postman dan uji endpoint PATCH /user/:id. Pertama, dapatkan sebuah data user dengan GET /user/:id yang sudah kamu buat sebelumnya. Contohnya bisa kamu lihat pada gambar berikut.
Mendapatkan salah satu data user dengan GET /user/:id
Kedua, lakukan update dengan PATCH /user/:id. Di sini kamu bisa menambahkan data apa pun yang diinginkan. Apabila ada property yang gak ada sebelumnya, maka akan ditambahkan. Kalau sudah ada dan nilai perubahannya berbeda, maka nilai property tersebut akan diubah. Berikut adalah tampilan apabila perubahan data berhasil dilakukan.
Perubahan data berhasil dilakukan.
Terakhir, cek data user yang sudah diubah datanya tersebut. Kamu akan melihat perubahan dan penambahan property pada data user tersebut:
Berhasil mendapatkan data yang berhasil diubah.
Menghapus User
Di bagian terakhir ini, kita akan menambahkan fungsi deleteOne() untuk menghapus salah satu data user yang dipilih.
MongoDB Connector
Kita akan menambahkan fungsi async deleteOne() pada file mongoDbConnector.js. Lihatlah potongan kode di bawah berikut.
// mongoDbConnector.js class MongoDbConnector { … async deleteOne(collection, filter) { try { const res = await this.db.collection(collection).deleteOne(filter); const { n, ok } = res.result; return n > 0 && ok ? ‘Successfully deleted data’ : ‘Failed to delete data’; } catch (err) { throw err; } } … } |
Fungsi ini memerlukan 2 parameter, yaitu collection dan filter. Kemudian tambahkan fungsi db.collection(collection).deleteOne(filter) di dalam block try-catch untuk menghapus 1 data yang memenuhi syarat filter.
Hasil dari operasi ini akan digunakan untuk mengembalikan pesan sukses apabila memenuhi syarat dari res.result.n > 0 dan res.ok, dan pesan gagal kalau gak terpenuhi.
index.js
Di file ini, perubahan akan dilakukan pada DELETE /user/:id. Maka, perhatikanlah perubahan pada app.delete() pada potongan kode di bawah ini.
// index.js … app.delete(‘/user/:id’, async (req, res) => { const result = await mongoDbConnector.deleteOne( collection, { _id: ObjectId(req.params.id) } ); res.send(result); }); … |
Pertama, tambahkan async pada fungsi callback dari app.delete(‘/user/:id’). Berikutnya, tambahkan mongoDbConnector.deleteOne() untuk menjalankan fungsi penghapusan data yang dibuat sebelumnya. filter yang digunakan adalah _id yang didapatkan dari req.params.id. Terakhir, kembalikan hasilnya dengan fungsi res.send(), sebagai respons dari pemanggilan DELETE /user/:id.
Lakukan Code Testing
Jalankan kembali npm start pada service ini. Dan buka kembali Postman untuk mencoba endpoint ini. Pertama, kita akan mendapatkan salah satu data yang ada di database seperti gambar berikut.
Gunakan GET /user/:id untuk mendapatkan salah satu data user.
Pastikan data tersebut ada, karena kamu gak bakal bisa menghapus data yang gak pernah ada sebelumnya. Setelah data dipastikan ada, kamu bisa mencoba mengakses DELETE /user/:id untuk menghapus data tersebut. Apabila berhasil, sebuah pesan sukses akan dimunculkan.
Penghapusan data berhasil dilakukan.
Untuk memastikan data user tersebut benar-benar terhapus, kamu bisa mengakses GET /user/:id dengan id yang sama seperti sebelumnya. Apabila muncul pesan “Data not found”, ini berarti proses penghapusan yang dilakukan sudah berhasil.
Ternyata data user berhasil dihapus. Kamu bisa lega.
Penutup
Selamat, kamu akhirnya berhasil menyelesaikan bagian 2 yang panjang ini! Jadi, inilah hal-hal yang sudah kamu pelajari:
- instalasi MongoDB,
- membuat sebuah konektor MongoDB dalam bentuk class,
- membuat koneksi dengan MongoDB,
- mengimplementasikan beberapa operasi CRUD MongoDB dengan Node.js, dan
- mengintegrasikan MongoDB Connector dengan API route yang sudah dibuat.
Dan inilah source code komplet untuk bagian 2 ini. Kira-kira apa yang kamu lewatkan? Atau mungkin bisa kamu buat jadi lebih baik? Jangan ragu untuk komentar di bawah! Sedikit spoiler, aku bakal mau sharing mengenai caching dengan Redis nih. Kamu tertarik gak, ya? Semoga artikel ini membantu kamu ya! Thanks for reading!
Comments ( 0 )