Nodejs – Create first REST API with expressjs

Expressjs Framework

Ini adalah tulisan pertama saya tentang nodejs.
Hal yang sangat menarik tentunya mengingat nodejs juga sedang begitu diminati terutama bagi para Javascript developer.
Ada banyak hal sebenarnya yang ingin saya tulis,
namun saya coba menulis dari hal-hal yang saya anggap sederhana
dan kemungkinan akan banyak saya pakai kedepannya.
Pada akhirnya membahas REST API di nodejs yang jadi pilihan saya.

Ada banyak framework di nodejs yang telah mengakomodir hal ini,
namun saya coba menggunakan expressjs karena merupakan salah satu yang paling populer dan mudah untuk ditemukan tutorialnya.

Ada banyak tutorial diluar sana yang tentunya sangat membantu saya dalam memahami bagaimana untuk membuat REST API untuk pertama kali.
Namun tentunya tetap dengan style saya dan dengan beberapa perbaikan di beberapa tempat.

Okey, kita mulai saja…

Semua code sudah tersedia di github saya di : https://github.com/mazipan/nodejs-simple-restfull-with-express

1. Saya mesti mencari IDE yang nyaman untuk menulis code nodejs dan pilihan saya ada pada Sublime Text 3 dan WebStorm (*licensed IDE).
2. Saya juga memilih menggunakan expressjs karena telah terdapat generator project, semacam template ketika kita akan membuat satu project.
3. Saya menggunakan mongooDB dengan mongoose sebagai library di nodejs.
4. Saya memanfaatkan fitur template generator yang disediakan oleh webStorm dengan memilih express sebagai framework generatornya.
5. Saya mesti menambahkan depedency mongoose yang tidak terdapat pada bawaan generator, kurang lebih seperti berikut package.json saya :

{
  "name": "nodejs-restfull-basic",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.13.2",
    "cookie-parser": "~1.3.5",
    "debug": "~2.2.0",
    "express": "~4.13.1",
    "mongoose": "~3.6.13",
    "jade": "~1.11.0",
    "morgan": "~1.6.1",
    "serve-favicon": "~2.3.0"
  }
}

6. Saya mesti membuat connector ke database, maka saya buat file terpisah dengan nama connection.js, sebagai berikut :

/**
 * Created by irfan.maulana on 11/24/2015.
 */
var mongoose = require('mongoose');

var conn = mongoose.connect('mongodb://localhost/restapi_database');

mongoose.connection.on('open', function (ref) {
    connected=true;
    console.log('open connection to mongo server.');
});

mongoose.connection.on('connected', function (ref) {
    connected=true;
    console.log('connected to mongo server.');
});

mongoose.connection.on('disconnected', function (ref) {
    connected=false;
    console.log('disconnected from mongo server.');
});

mongoose.connection.on('close', function (ref) {
    connected=false;
    console.log('close connection to mongo server');
});

mongoose.connection.on('error', function (err) {
    connected=false;
    console.log('error connection to mongo server!');
    console.log(err);
});

mongoose.connection.db.on('reconnect', function (ref) {
    connected=true;
    console.log('reconnect to mongo server.');
});

module.exports = conn;

7. Saya juga membuat model yang akan menjadi semacam ORM bagi mongoose, saya buat file product.js, sebagai berikut :

/**
 * Created by irfan.maulana on 11/24/2015.
 */
var mongoose = require('../connection/connection');

var Schema = mongoose.Schema;
var Product = new Schema({
    title: { type: String, required: true },
    description: { type: String},
    price: { type: Number},
    modified: { type: Date, default: Date.now }
});
var ProductModel = mongoose.model('Product', Product);

module.exports = ProductModel;

8. Ini bagian paling penting, saya mesti membuat satu file route dengan nama product.js,
file ini berisi REST API yang kita buat harus diakses dari url mana serta akan mengembalikan response apa
dan logic apa yang akan dikerjakan di dalamnya, sebagi berikut :

/**
 * Created by irfan.maulana on 11/24/2015.
 */
var express = require('express');
var ProductModel = require('../model/product');

var router = express.Router();

router.get('/', function (req, res){
    return ProductModel.find(function (err, products) {
        if (!err) {
            return res.send({result : true, products : products});
        } else {
            console.log(err);
            return res.send({result : false, errorDesc : "Failed get data from DB."});
        }
    });
});

module.exports = router;

*update : saya mengubah pembuatan route menjadi sperti berikut untuk mengurangi kesalahan penulisan path url :

/**
 * Created by irfan.maulana on 11/24/2015.
 */
var express = require('express');
var ProductModel = require('../model/product');

var router = express.Router();

router.route('/')

    .get(function (req, res){
            return ProductModel.find(function (err, products) {
                if (!err) {
                    return res.send({result : true, products : products});
                } else {
                    console.log(err);
                    return res.send({result : false, errorDesc : "Failed get data from DB."});
                }
            });
    })

    .post(function (req, res){
        var product;
        var errorMessage = "";
        if(typeof req !== 'undefined'){
            if(req.body.title === null || req.body.title === ""){
                errorMessage = "Title product is null or empty.";
                return res.send({result : false, errorDesc : errorMessage});
            }else{
                product = new ProductModel({
                    title: req.body.title,
                    description: req.body.description,
                    price: req.body.price
                });

                product.save(function (err) {
                    if (!err) {
                        console.log("product : "+product.title + " has been created ");
                        return res.send({result : true, product : product});
                    } else {
                        console.log(err);
                        return res.send({result : false, errorDesc : err});
                    }
                });

            }
        }else{
            errorMessage = "Request is null or empty.";
            return res.send({result : false, errorDesc : errorMessage});
        }
    });

module.exports = router;

9. Kita akan memanggil file route yang kita buat di app.js, sebagai berikut :

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var products = require('./routes/products');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/api/products', products);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

module.exports = app;

10. Terakhir adalah file bawaan dari generator webStorm IDE yakni www yang terletak di folder bin,
file ini akan mengeksekusi file app.js kita, sebagai berikut :

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('nodejs-restfull-basic:server');
var http = require('http');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

Dan selesai sudah REST-API pertama yang kita buat dengan sederhana menggunakan nodejs, berikut list API yang telah kita buat :

NAME URL METHOD
Get All Product localhost:3000/api/products GET
Get Product By Id localhost:3000/api/products/{id} GET
Insert Product localhost:3000/api/products POST
Update Product By Id localhost:3000/api/products/{id} PUT
Delete Product By Id localhost:3000/api/products/{id} DELETE

Terima kasih dan semoga bermanfaat.

mazipan-signature

One thought on “Nodejs – Create first REST API with expressjs

Be a good reader, leave your comment please.

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s