July 14, 2016

Xây dựng ứng dụng API với NodeJS - Phần 2.1: CRUD - Create

source: https://scotch.io/wp-content/uploads/2014/04/restful-api-node-express-4-router.jpg
Ở phần trước, chắc hẳn không ít bạn sẽ (tự) hỏi tại sao không là MongoDB mà là MySQL? MongoDB không phải là thời thượng ah? MySQL già cõi rồi xài chi?...Vô số câu hỏi được đặt ra. Và câu trả lời của mình tại sao loạt bài này dùng MySQL mà không dùng MongoDB

Nói một câu đơn giản, dễ hiểu, xúc tích nhất là: "Mình thích"
Nói một cách cụ thể hơn là: "MongoDB với NodeJS thì nó nhan nhãn hằng ha sa số rồi, thêm 1 bài hay bớt 1 bài cũng không có gì. Một phần nữa MySQL cũng khá thân quen rồi, nên tiếp cận dễ hơn cho đa số người."

Sequelize là gì?

Đây là một package ORM cho một số hệ cơ sở dữ liệu như MSSQL, PostgreSQL, SQLite và chắc chắn là phải có MySQL rồi. Khi bạn dùng generator để tạo project như phần 1, thì tự động nó sẽ cài đặt gói Sequelize này cho bạn.

Để hiểu rõ hơn nữa cũng như biết cách dùng package này một cách chi tiết thì cách bạn đến trang chủ Sequelize của nó để tham khảo. Bài viết này chỉ minh họa cách thức xử lý ORM một phần nào, không phải dịch toàn bộ sang tiếng Việt ^^

Cấu trúc cơ sở dữ liệu

Với cách viết của mình, mình sẽ tinh chỉnh một số cho phù hợp phong cách code của mình, mọi người không nhất thiết làm theo, vì đây không phải là cách duy nhất.

Việc đầu tiên, mình sẽ xóa tập tin article.js trong thư mục app/models vì mình không cần tới file này trong demo này. Tiếp theo mình cũng chỉnh đôi điều trong tập tin index.php cũng trong thư mục app/models.
var Sequelize = require('sequelize'),
  config = require('../../config/config'),
  dbConfig = config.db_config;

var sequelize = new Sequelize(dbConfig.database, 
                              dbConfig.username, 
                              dbConfig.password, 
                              dbConfig.options);

module.exports = {
  sequelize: sequelize,
  Sequelize: Sequelize
};

Tiếp theo, mình sẽ tạo ra một tập tin mới schemas.js trong thư mục app.models này để khởi tạo cấu trúc cơ sở dữ liệu.
var Sequelize = require('sequelize');
module.exports = function (sequelize) {
  var User = sequelize.define('User', {
    username: {type: Sequelize.STRING(250), allowNull: false, unique: true},
    password: {type: Sequelize.STRING, allowNull: false},
    first_name: Sequelize.STRING,
    last_name: Sequelize.STRING,
    address: Sequelize.STRING,
    avatar_url: Sequelize.STRING,
    phone_number: Sequelize.STRING,
    last_logged_in: Sequelize.DATE,
    status: {type: Sequelize.BOOLEAN, defaultValue: true}
  }, {
    timestamps: true,
    underscored: true,
    tableName: 'users'
  });

  return {
    User: User
  };
}

Services

Đây chỉ là cách mình thích làm, mặc dù dùng ORM, nhưng theo quan điểm cá nhân, vẫn thích rạch ròi giữa tầng xử lý dữ liệu với xử lý route/controller. Thông thường, thì theo mô hình MVC thì phần (M)odel chính là dùng để tương tác dữ liệu. Nhưng vì Sequelize là ORM tương tác rồi, cấu trúc này lại tạo sẵn thư mục models rồi, nên mình tách ra thư mục services để tiện quản lý, code, tests thôi.

Ở đây mình tạo ra một thư mục mới mang tên là services, và một tập tin là user.js có nội dung như sau:
var _ = require('underscore');

module.exports = function (sequelize) {
  var User = require('../models/schemas')(sequelize).User;

  return {
    addNewUser: function (user, cb) {
      User.create(user)
        .then(function(instance){
          return cb(null, _.clone(instance.dataValues));
        })
        .catch(function (error) {
          return cb(error);
        });
    }
  }
};

Ở đây, để đơn giản hóa vấn đề, mình chỉ thực hiện việc lưu đối tượng user xuống cơ sở dữ liệu thông qua phương thức create() được cung cấp bởi Sequelize. Sau khi đã insert thành công, mình sẽ trả về giá trị lưu trữ. Các bạn thấy ở đây mình dùng thư viện underscorejs nhằm mục đích tạo một đối tượng clone của kết quả trả về. Đây cũng chỉ là thói quen của mình.

Controller - Router

Cuối cùng, chúng ta xây dựng controller cũng là router để chịu trách nhiệm tạo thêm user mới vào cơ sở dữ liệu. Ở đây chúng ta đã có folder controllers, chúng ta sẽ tạo thêm một tập tin trong thư mục này, mang tên user.js, có nội dung như bên dưới
var validator = require('validator'),
  express = require('express'),
  router = express.Router(),
  db = require('../models'),
  userService = require('../services/user')(db.sequelize);

module.exports = function (app) {
  app.use('/user', router);
};

router.post('/', function (req, res, next) {
  var user = {
    email: req.body.email,
    password: req.body.password,
    first_name: req.body.first_name || null,
    last_name: req.body.last_name || null,
    address: req.body.address || null,
    phone_number: req.body.phone_number || null
  };

  if (!user.email || !validator.isEmail(user.email)) {
    var error = new Error('Email is required or is invalid email format');
    error.status = 400;
    return next(error);
  }

  if (!user.password) {
    var error = new Error('Password is required');
    error.status = 400;
    return next(error);
  }

  userService.addNewUser(user, function (error, createdUser) {
    if (error) {
      return next(error);
    }

    return res.json({message: "Successful", data: createdUser});
  })

});

Như đã cố tình đơn giản cho mọi người dễ tiếp cận vấn đề nhất, mình chỉ chủ yếu kiểm tra dữ liệu bắt buộc là email và password, trong đó email cần phải đúng định dạng. Như vậy là xong, bây giờ bạn hãy khởi chạy dự án này, dùng lệnh gulp để chạy như đã giới thiệu ở phần 1 loạt bài này. Sau khi đã khởi tạo thành công, bạn có thể dùng 1 công cụ nào đó test API vừa tạo, và cách đơn giản nhất là dùng công cụ CURL sẵn có.

curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'email=abc@demo.com&password=123456' "http://localhost:3000/user"

Và kết quả nhận về nếu không có lỗi gì sẽ hiển thị giống như sau:
{
  "message": "Successful",
  "data": {
    "status": true,
    "id": 1,
    "email": "abc@demo.com",
    "password": "123456",
    "first_name": null,
    "last_name": null,
    "address": null,
    "phone_number": null,
    "updated_at": "2016-07-08T13:05:31.000Z",
    "created_at": "2016-07-08T13:05:31.000Z"
  }
}

Như vậy là xong cho phần thứ nhất giới thiệu về CRUD với thư viện Sequelize. Mọi chuyện vẫn còn ở những phần tiếp theo, hy vọng sẽ sớm ra mắt để hỗ trợ được những ai quan tâm loạt bài này.

Phần 1: Khởi tạo kiến trúc

source:

git clone https://github.com/tmquang6805/api-express-tut-demo.git api_tut
cd api_tut
git checkout 65a53de

No comments:

Post a Comment