On 10/15/2012 01:18 AM, Mil Werns wrote:
@Tim:
Thanks, positive feedback is always welcome :)
@Eldar:
the-box looks very interesting. I am curious to see what in this
project happens next. But currently, it is important for me to use
only standard (within the meaning of established/mainstream)
componentes and libraries (like e.g. async) that every node programmer
knows.
Can you please point out some more details why you don't find this
code clean/easy maintainable? And give me some example code for
improvements?
It seems you are targeting db activities - since db's are so specific,
I'm not sure it makes sense to try for a generic framework but might be
more useful to have implementations for specific dbs. Couchdb is already
REST - with node it makes sense to have a change listener and maybe an
auth system. Mongodb is popular with Noders but lacks a js REST
interface (the one available is not very useful) so anything targeted
here would be quite useful. Might want to examine what python based
sleepy mongoose does along these lines. might also be nice to do a REST
interface for Postgres on the sql side.
On Sunday, October 14, 2012 11:58:31 AM UTC+2, Mil Werns wrote:
Hi,
I want to implement a REST API with node.js and restify. Because
it is my first node.js project, I spent some time to learn how to
structure the application to avoid the callback hell. Please have
a look to the following solution.
_*Assumptions*_
- This approach is for writing an end-user application, not a
module or a driver in the sense of a public library.
- REST services are closely related to CRUD, so we have a lot of
simple sequential/interdependent operations (get_data +
validate_data [+ change_data] + save_data).
_*Goals*_
*===> Focus is writing maintainable, clean and easy to understand
code! <===*
Conversely, this means...
- Performance is secondary (scaling horizontally if necessary).
- Avoid "low level" methods like process.nextTick(), instead use
"high level" methods/libs like middleware and control flow modules.
- Use modules to implement a well known MVC structure.
_*Code*_
Please ignore the poor logging, the not very useful view tasks
etc. in the following example. It should only demonstrate the MVC
/ callback structure.
*/* server.js */*
var restify = require("restify");
var router = require("./router");
...
router.route(server);
server.listen(...);
*/* router.js */*
var userController = require("./controllers/user");
... // more controllers
exports.route = function route(server) {
server.get("/users",
[
userController.checkRead,
userController.read,
]
);
server.put("/users",
[
userController.checkUpdate,
userController.update,
]
);
...
};
*/* controllers/user.js */*
var restify = require("restify");
var async = require("async");
var check = require('validator').check;
var sanitize = require('validator').sanitize;
var m = require("../models/user");
var v = require("../views/user");
...
var checkUpdate = function userCheckUpdate(req, res, next) {
// validate user input
try {
check(req.params.id <http://req.params.id>, "id").isInt();
check(req.params.forename, "forename").len(1,50);
check(req.params.surname, "surname").len(1,50);
check(req.params.email, "email").isEmail();
} catch(err) {
if(err) {
return next(new restify.InvalidArgumentError("Invalid
arguments"));
}
}
return next();
};
var update = function userUpdate(req, res, next) {
// create model
var model = {
forename: sanitize(req.params.forename).xss(),
surname: sanitize(req.params.surname).xss(),
email: sanitize(req.params.email).xss(),
};
//*** "sub-methods" part ***
// _example_ for data check
function checkOwner(curData, callback) {
if(curData.ownerId !== req.userId) {
return callback(new
restify.InvalidArgumentError("NotAuthorizedError"));
}
return callback(null, curData);
};
// _example_ for simple model manipulation
function addSimple(model, callback) {
model.updateDate = new Date().getTime();
return callback(null, model);
};
// _example_ for complex model manipulation
function addComplex(model, callback) {
// use async again to simulate synchronous/parallel/... flow
async.waterfall(
[
// do something
]
function(err, model) {
if(err) {
return callback(new restify.InternalError());
}
return callback(null, model);
}
);
};
// *** main part ***
// use async to simulate synchronous flow
async.waterfall(
[
function(aNext) { m.get(req.params.id
<http://req.params.id>, aNext); },
function(curData, aNext) { checkOwner(curData, aNext); },
function(curData, aNext) { addSimple(model, aNext); },
function(model, aNext) { addComplex(model, aNext); },
function(model, aNext) { m.update(model, aNext); },
function(model, aNext) { v.update(model, aNext); },
],
function(err, model) {
if(err) { return next(err); }
res.send(200, model);
}
);
return next();
};
...
*/* models/user.js */*
...
var get = function userGet(id, callback) {
var curData = ... // DB query for ID
if(err) {
console.log("DB error: " + err);
return callback(new restify.InternalError());
};
return callback(null, curData);
};
var update = ...
...
*/* views/user.js */*
...
var update = function userUpdate(model, callback) {
// adjust model for output
delete model.updateDate;
...
callback(null, model);
};
As you can see, this approach uses the middleware concept + async
module to separate the application in small (MVC) pieces that are
hopefully easy to understand.
But as I said before: I'm a node.js newbie :)
*What do you think about this structure?
Are there any drawbacks?*
Thanks a lot for your help
Mil
--
Job Board: http://jobs.nodejs.org/
Posting guidelines:
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en
--
Job Board: http://jobs.nodejs.org/
Posting guidelines:
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en