Hi, this looks nice. I will use the middleware approach in your routers ;-) 

Since i am learning myself you might want to question my "tip".

Instead of a structure like:

- controller
-- userController
-- nextController
-- and so on

- views
-- userView
-- nextView
-- and so on

- models
-- userModel
-- nextModel
-- and so on

- onlyOneRouter.js



I personally find it very helpful to structure the mvc separated in 
modules. Also the router like:

- modules/

-- userModule/
--- UserController.js
--- Router.js
--- models/
---- UserModel.js
--- views/
---- UserView.js

-- nextModule/
--- NextController.js
--- Router.js
--- models/
---- NextModel.js
--- views/
---- NextView.js

This way you separate your routers too. I personally 
found https://github.com/visionmedia/express/tree/master/examples/mvc very 
helpful for structuring. I also like how the app is separated in "sub-apps" 
via the lib/boot.js in the mvc example from express.

If i got something wrong, please feel free to correct me ;-)

Am Sonntag, 14. Oktober 2012 11:58:31 UTC+2 schrieb Mil Werns:
>
> 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, "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, 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

Reply via email to