11.01.2014

Membuat CRUD Sederhana Dengan Node.js, MongoDB, Express dan AngularJS Part 1


Setelah kita berhasil membuat Hello World dengan menggunakan Node.js dan Express. Disini kita akan melanjutkan dengan membuat API CRUD sederhana dengan Node.js, Express, dan MongoDB. Jika belum pernah menggunakan node.js dan express, sebaiknya ikuti tutorial ini terlebih dahulu untuk beberapa penjelasan awal, tahap installasi node.js sampai pembuatan hello world.

MongoDB


MongoDB adalah OpenSource NoSQL database document yang cepat dan kuat (JSON-Style document) yang ditulis dalam C++ juga.

Mongoose


Mongoose adalah suatu ODM (Object Dokumen Mapper) untuk objek pemodelan yang menyediakan lapisan untuk menulis validasi pada MongoDB, casting dan logika bisnis antara fitur-fitur lainnya.

Angular.js


Angular.js adalah sebuah client-side MVVM (Model-View-View-Model) framework untuk membangun aplikasi web satu halaman. Kami akan menggunakannya pada tutorial part 2 untuk berinteraksi dengan API yang kami buat dengan Node.js pada tutorial part 1 ini.



1- Instalasi modul

Lakukan pembuatan project dasar (file app.js dan package.json) dan pemasangan package express seperti pada link ini, kemudian lanjutkan dengan memasang mongoose dengan menjalankan perintah ini pada command prompt (pastikan sudah masuk kedalam folder dimana app.js dan package.json disimpan):

npm install mongoose --save

jika berhasil maka tampilan command prompt akan seperti ini:


Pada Express 4, modul bodyParser, methodOverride and morgan merupakan modul yang terpisah sehingga kita perlu menginstallnya satu-persatu.

npm install morgan --save
npm install body-parser --save
npm install method-override --save

Jika kita lihat file package.json sekarang, maka akan seperti ini:


2- Membuat app models

Disini kita akan membuat file model yang berfungsi sebagai representasi objek pada sistem komputer berikut dengan atribut dan relasinya. Dalam tutorial ini, kita akan membuat model sebuah mobil.

Buatlah sebuah folder bernama models dan didalamnya buat sebuah file bernama car.js, lalu tambahkan kode dibawah ini:

/**
 * Car
 *
 * @module      :: Model
 * @description :: Represent data model for the Cars
 * @author      :: Asep Maulana Ismail
 */

var mongoose = require('mongoose');
var Schema = mongoose.Schema;


var Car = new Schema({

  model:    {
    type    : String,
    require : true
  },
  year:   {
    type: String,
    require : true
  },
  color:   {
    type: String,
    require : true
  },
  price :   {
    type    : Number,
    require : true
  },
  modified: {
    type    : Date,
    default : Date.now
  }
});

Car.path('model').validate(function (v) {
  return ((v != "") && (v != null));
});

module.exports = mongoose.model('Car', Car);

Kita telah membuat skema baru dari sebuah mobil yang memiliki atribut model, year, color, price dan modified yang akan berubah jika kita melakukan update.


3- Menghubungkan aplikasi dengan MongoDB

Kita harus menghubungkan aplikasi kita dengan MongoDB dimana kita akan menyimpan dokumen.

Langkah pertama, kita harus memasang MongoDB nya pada komputer kita dengan mengikuti langkah-langkah yang ada pada website MongoDB.

Jika sudah berhasil diinstall, jalankan mongod.exe yang ada pada folder instalasi MongoDB.


Lalu, tambahkan kode dibawah ini pada file app.js :

var morgan = require('morgan'); var bodyParser = require('body-parser'); var methodOverride = require('method-override'); var mongoose = require("mongoose");

dan

app.use(morgan('dev')); app.use(bodyParser.json());
app.use(methodOverride());

dan

// MongoDB configuration mongoose.connect('mongodb://localhost/car', function(err, res) {   if(err) {     console.log('error connecting to MongoDB Database. ' + err);   } else {     console.log('Connected to Database');   } });

Secara keseluruhan, file app.js akan terlihat seperti ini:

/*
 * Main App file App.js
 * @author Asep Maulana Ismail
 */



// Dependencies requirements, Express 4
var express        = require('express');
var app            = express();

var morgan         = require('morgan');
var bodyParser     = require('body-parser');
var methodOverride = require('method-override');
var mongoose        = require("mongoose");

app.use(express.static(__dirname + '/public'));
app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(methodOverride());

// MongoDB configuration
mongoose.connect('mongodb://localhost/car', function(err, res) {
  if(err) {
    console.log('error connecting to MongoDB Database. ' + err);
  } else {
    console.log('Connected to Database');
  }
});


app.listen(8080);
console.log('Im listening on port 8080');

// First example router
app.get('/', function(req, res) {
  res.send("Hello world!");
});

Jika kita menjalankan kembali aplikasinya, maka output dari console akan seperti ini:

Im listening on port 8080
Connected to Database

Kita sudah berhasil menghubungkan aplikasi kita dengan database, sekarang kita akan membuat sebuah routes (a.k.a controller).

4- Membuat routes dan binding action

Buatlah sebuah folder bernama routes dan buat sebuah file didalam folder tersebut dengan nama car.js, dan masukan kode berikut:

/**
 * Car
 *
 * @module      :: Routes
 * @description :: Maps routes and actions
 * @author      :: Asep Maulana Ismail
 */

var Car = require('../models/car.js');

module.exports = function(app) {


  /**
   * Find and retrieves all cars
   * @param {Object} req HTTP request object.
   * @param {Object} res HTTP response object.
   */
  findAllCars = function(req, res) {
    console.log("GET - /cars");
    return Car.find(function(err, cars) {
      if(!err) {
        return res.send(cars);
      } else {
        res.statusCode = 500;
        console.log('Internal error(%d): %s',res.statusCode,err.message);
        return res.send({ error: 'Server error' });
      }
    });
  };



  /**
   * Find and retrieves a single car by its ID
   * @param {Object} req HTTP request object.
   * @param {Object} res HTTP response object.
   */
  findById = function(req, res) {

    console.log("GET - /car/:id");
    return Car.findById(req.params.id, function(err, car) {

      if(!car) {
        res.statusCode = 404;
        return res.send({ error: 'Not found' });
      }

      if(!err) {
        return res.send({ status: 'OK', car:car });
      } else {

        res.statusCode = 500;
        console.log('Internal error(%d): %s', res.statusCode, err.message);
        return res.send({ error: 'Server error' });
      }
    });
  };




  /**
   * Creates a new car from the data request
   * @param {Object} req HTTP request object.
   * @param {Object} res HTTP response object.
   */
  addCar = function(req, res) {

    console.log('POST - /car');

    var car = new Car({
      model:    req.body.model,
      year:    req.body.year,
      color:    req.body.color,
      price:    req.body.price
    });

    car.save(function(err) {

      if(err) {

        console.log('Error while saving car: ' + err);
        res.send({ error:err });
        return;

      } else {

        console.log("Car created");
        return res.send({ status: 'OK', car:car });

      }

    });

  };



  /**
   * Update a car by its ID
   * @param {Object} req HTTP request object.
   * @param {Object} res HTTP response object.
   */
  updateCar = function(req, res) {

    console.log("PUT - /car/:id");
    return Car.findById(req.params.id, function(err, car) {

      if(!car) {
        res.statusCode = 404;
        return res.send({ error: 'Not found' });
      }

      if (req.body.model != null) car.model = req.body.model;
      if (req.body.year != null) car.year = req.body.year;
      if (req.body.price != null) car.price  = req.body.price;
      if (req.body.color != null) car.color = req.body.color;

      return car.save(function(err) {
        if(!err) {
          console.log('Updated');
          return res.send({ status: 'OK', car:car });
        } else {
          if(err.name == 'ValidationError') {
            res.statusCode = 400;
            res.send({ error: 'Validation error' });
          } else {
            res.statusCode = 500;
            res.send({ error: 'Server error' });
          }
          console.log('Internal error(%d): %s',res.statusCode,err.message);
        }

        res.send(car);

      });
    });
  };



  /**
   * Delete a car by its ID
   * @param {Object} req HTTP request object.
   * @param {Object} res HTTP response object.
   */
  deleteCar = function(req, res) {

    console.log("DELETE - /car/:id");
    return Car.findById(req.params.id, function(err, car) {
      if(!car) {
        res.statusCode = 404;
        return res.send({ error: 'Not found' });
      }

      return car.remove(function(err) {
        if(!err) {
          console.log('Removed car');
          return res.send({ status: 'OK' });
        } else {
          res.statusCode = 500;
          console.log('Internal error(%d): %s',res.statusCode,err.message);
          return res.send({ error: 'Server error' });
        }
      })
    });
  }

  //Link routes and actions
  app.get('/car', findAllCars);
  app.get('/car/:id', findById);
  app.post('/car', addCar);
  app.put('/car/:id', updateCar);
  app.delete('/car/:id', deleteCar);

}

Disana, kita mendefinisikan routes dari fungsi-fungsi dari CRUD.

findAllCars, berfungsi untuk mengambil semua data mobil yang ada pada database.
findById, berfungsi untuk mengambil data sebuah mobil berdasarkan parameter id.
addCar, berfungsi untuk menambahkan data mobil baru kedalam database.
updateCar, berfungsi untuk memperbarui data mobil yang sudah ada didatabase berdasarkan parameter id.
Dan terakhir adalah fungsi deleteCar, berfungsi untuk menghapus data sebuah mobil berdasarkan parameter id.

Sebelum kita mencobanya, tambahkan kode dibawah ini pada file app.js (tepat sebelum koneksi ke MongoDB) sebagai deklarasi routes.


routes = require('./routes/car')(app);

Langkah selanjutnya, kita akan melakukan testing API aplikasi kita menggunakan aplikasi ChromeChrome's Postman REST Client.

5- Tes API

Buka aplikasi Postman, lalu tambahkan /car pada url:


Kita akan mendapatkan hasil [], karena kita memang belum memiliki data mobil dalam database.

Buatlah sebuah data mobil dengan ganti method GET menjadi POST dan tambahkan data mobil untuk dijadikan sebagai parameter API kita (model, year, color, price).


Dan jika kita mengirimkan request tersebut, sebuah data mobil berhasil disimpan.

Lalu, kita coba lagi melakukan GET request pada /car, maka hasilnya akan berbeda dengan hasil pertama:


Sekarang kita coba memanggil fungsi update:


Jika kita kirim request tersebut, maka harga mobil akan menjadi 50.000.000. Pastikan bahwa harga mobil sudah ter-update.



Terakhir, kita coba method delete.



Jika kita menekan tombol Send, maka akan seperti ini yang artinya data mobil sudah berhasil terhapus.




Kita sudah berhasil membuat API untuk melakukan CRUD, tutorial selanjutnya insya Allah kita akan membuat bagian front-end nya dengan Angular.js dan juga menggunakan API ini.

Code at github

Jika mengalami kesulitan mengikuti tutorial ini atau punya beberapa pertanyaan, bisa tulis di bagian komentar atau download contoh kode nya disini.

Semoga bermanfaat, terima kasih.

20 comments:

  1. thanks tutorialnya gan tpi ana ada error nh di validasinya tpi klau ana hapus validasinya berhasil gan, kira2x knp ya gan ? apa krna bda versi ? errornya sprti ini :

    /home/rizki/BelajarCRUDAPINodeJS/models/mahasiswa.js:23
    Mahasiswa.path('model').validate(function (v) {
    ^
    TypeError: Cannot call method 'validate' of undefined
    at Object. (/home/rizki/BelajarCRUDAPINodeJS/models/mahasiswa.js:23:25)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object. (/home/rizki/BelajarCRUDAPINodeJS/routes/mahasiswa.js:4:17)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)

    ReplyDelete
    Replies
    1. kemungkinan sih di class Mahasiswa nya itu ga ada attribut model, kalo boleh , coba copas bagian deklarasi model class Mahasiswa nya

      Delete
    2. var mongoose = require('mongoose');
      var Schema = mongoose.Schema;

      var Mahasiswa = new Schema({
      npm:{
      type:String,
      require:true
      },
      nama:{
      type:String,
      require:true
      },
      kelas:{
      type:String,
      require:true
      }
      });

      Mahasiswa.path('model').validate(function (v) {
      return ((v != "") && (v != null));
      });

      module.exports = mongoose.model('Mahasiswa', Mahasiswa);

      Delete
    3. kata 'model' disini -> Mahasiswa.path('model').validate adalah attribut yang ada pada class (bisa diliat di source diatas bahwa class Car memiliki atribut Model), jadi di kalo dimahasiswa itu kan ga ada model, seharusnya kata 'model' diganti dengan atribut yang akan di validasi, entah itu npm, nama, atau kelas.. :)

      Delete
    4. owh iya gan :D ana kira itu bawaan dari Node JS nya :) maklum gan baru bljr Node JS. biasanya ana di Java sama angularJS. nice post :) thanks

      Delete
    5. sama2 gan, sama ane juga masih belajar, dan malahan baru tau tadi itu juga haha .. makasih juga gan udah baca blog ane :)

      Delete
  2. mas itu ko yang buat update ada req.body.size ???
    deklarasi update buat price nya mana??

    ReplyDelete
    Replies
    1. oh iya maaf, itu harusnya price, lupa ngeganti.. hha thx gan nanti saya update

      Delete
    2. kalo di source yang di github itu udah bener

      Delete
  3. oya mas, ko saya update price....
    yang ke update malah color....
    notifikasi Ok ...

    ReplyDelete
    Replies
    1. mungkin ada yang salah mas, saya ngecek sih source diatas harusnya udah bener :)

      Delete
  4. Septttt... Udah bener mass....

    Thanks For Fast Respons.....

    ReplyDelete
    Replies
    1. sipp gan (Y) sering2 mampir aja, ane belum sempet nulis lg hhe padahal banyak yang mau di share

      Delete
  5. Keren Mas ,, Terimakasih Banyak Ilmunya ,,

    ReplyDelete
  6. Mas mau nanya kok waktu mau ngejalanin node app.js nya malah muncul kaya gini
    error connecting to MongoDB Database. MongoError: failed to connect to server [localhost:27017] on first connect [MongoError: connect ECONNREFUSED 127.0.0.1:27017]
    itu gimana fixnya yah ?

    ReplyDelete
    Replies
    1. mongodb nya belum jalan, coba jalankan dulu service mongodb nya , baru ke node app.js

      Delete
    2. This comment has been removed by the author.

      Delete