Bạn có chắc chắn muốn xóa bài viết này không ?
Bạn có chắc chắn muốn xóa bình luận này không ?
Cải tiến ExpressJS Routing
Vấn đề
Thời gian gần đây, do yếu tố công việc nên mình phải tiếp xúc nhiều với NodeJS, đâm ra cũng có tí thích thú muốn tìm hiểu sâu hơn về em nó.
Hôm rồi mình có đá qua tìm hiểu về ExpressJS - một framework rất nổi của NodeJS - chắc ai cũng biết rồi nên mình không nói lại nữa.
Mình rất kết cấu trúc Middleware của nó, vừa dễ hiểu mà lại dễ mở rộng, tích hợp. Tuy nhiên có điểm trừ là Routing của nó theo mình nghĩ là không được tốt lắm.
Cụ thể Routing Basic của nó như sau:
// will match request to the root
app.get('/', function (req, res) {
res.send('root');
});
// will match requests to /about
app.get('/about', function (req, res) {
res.send('about');
});
Tại sao lại không tốt?
Thử tưởng tượng system của bạn có rất nhiều api ( với hệ thống game lớn vài trăm API là bình thường) thì bạn sẽ thấy những bất tiện sau:
- File route ngày một phình to và khó quản lý
- Mỗi lần thêm API mới bạn lại thêm một công sửa file route
- Tính mở rộng và tích hợp không cao ….
Vậy tại sao ta không cải tiến cho dễ sử dụng hơn một chút :)
Ý tưởng
Ý tưởng cải tiến của mình bắt nguồn dựa trên kinh nghiệm code PHP, hồi còn dùng Yii framework. Chỉ cần format URL lúc đầu, controller,action code đúng format là chạy.
Tuy nhiên ở đây không đơn giản như vậy. Mình sẽ định nghĩa route ngay trên mỗi API bằng comment.
Tiến hành
Cùng nhìn lại cách khai báo route basic:
app.get('/action1', function (req, res) {
res.end(‘Hello World!');
});
Trong đó có Method: GET và URI: '/action1'
Chúng ta sẽ chuyển về TestController và khai báo như sau:
/**
* [action1 description]
* @param req [description]
* @param res [description]
* @uri /action1
* @mtype Get
*/
TestController.prototype.action1 = function(req,res){
var content = '<h1> Hello World! </h1>';
res.end(content);
}
Như vạy chúng ta đã định danh API ở comment là: @uri /action1 và @mtype GET
Việc còn lại là sao để cho express tự động hiểu được định danh đó mà không cần config gì thêm.
Để đọc được comment, ta sử dụng jsdoc-parse và tạo một file router setup như sau.
/**
* Add function that has @uri and @mtype tag to express router
* @param {Object} app Express Application
* @param {Object} comments list of comments in controller
* @param {Object} module object controller
*/
function parseComentToRouter(app,comments,module){
for (var i = 0; i < comments.length; i++) {
var comment = comments[i];
// if it is not function then return
if (comment.kind && comment.kind == 'function') {
var method,uri,j;
for( j in comment.customTags){
var cTags = comment.customTags[j];
if(cTags.tag == 'uri'){
uri = cTags.value;
}
else if(cTags.tag == 'mtype'){
method = cTags.value;
}
}
var func = comment.id && module.__proto__[comment.id.split('#')[1]];
if (method && uri) {
// add action vào express
app[method.toLowerCase()](uri, func);
console.log('[ URL Routing ] Add' + comment.id + 'method :' + method);
} else {
console.log('[ URL Routing ] Failure' + comment.id);
}
}
}
}
/**
* Setup router by dir
* ex: projectDir/controllers
* @param {Object} app Express application
* @param {String} dir Controller path
*/
Routes.prototype.setup = function(app,dir){
// Get list các file trong dir
fs.readdirSync(dir)
.filter(function(v) {
if (v === 'index.js') {
return false;
}
// chỉ giữ lại các file có đuôi .js
return v.slice(v.lastIndexOf('.')) === '.js';
})
// tiến hành parse comment trong các file
.forEach(function(name) {
var module;
var path = dir + '/' + name;
try {
module = require(path);
} catch(e) {
console.log('[ URL Routing ] Failure can not load module');
return;
}
var commentStream = parse({src: path});
commentStream.on('data',function(data){
var comments = JSON.parse(data.toString());
// sử lý comment
parseComentToRouter(app,comments,module);
// console.log(comments);
});
});
};
khi chạy ta sẽ được kết quả như sau:
expressjs-routing git:(master) node app.js
[ URL Routing ] Failuretest
[ URL Routing ] AddTestController#action1method :Get
[ URL Routing ] AddTestController#action2method :Get
Mình thừa nhận là hơi kém trong việc giải thích nên mọi người có thể down source về chạy thử tại đây:
https://github.com/sukoshi/expressjs-routing
Chúc các bạn cuối tuần vui vẻ




