8

The app is using express 3. Here is a barebones example of a route that fetches data from the database:

var Post = mongoose.model('Post')

app.get('post/:id/loompas', function(req, res) {
    Post.getLoompas(function(err, data){
        res.render('x', data)
    })
})

Where Posts.getSomeData is defined as instance methods in /models/post.js, and sometimes accesses external APIs:

PostSchema.method('getLoompas', function(callback){
    var post = this
    API.get('y', function(x){
        this.save(x)
        callback(x)
    })
})

This is starting to smell, and doesn't look like it belongs along the Schema definition. The collection of methods could grow quite large.

What design patterns are recommended to separate these concerns and avoid extremely fat models? A service layer for external API calls? Any interesting solutions out there?

Ricardo Tomasi
  • 34,573
  • 2
  • 55
  • 66
  • I recently came across [this post](http://www.edave.net/2011/03/22/a-layered-node-js-architecture-using-express/). The author does not use mongoose and builds his own service and DAO layers. It might sound like reinventing the wheel in the age of ORMs, but coming from a J2EE background, this setup makes more sense to me in terms of clean code. In your case, I think your external API caller code can safely reside in the service layer. – Vasan Dec 30 '15 at 12:14

2 Answers2

1

This does indeed smell a little bit. I would use the approach of considering your web app merely as a view of your application.

The best way to ensure this is to never use your mongoose models from your webapp. You could have your webapp living in a process and your model specific logic in another process. The job of that second process would be to take care of your business logic and persistence layer (mongoDB), making it the M in MVC.

Accessing external APIs would take place in that Model layer, we your can separate it from your persistence implementation.

There's a way of communicating between node processes that I like, it's dnode. Once set up, it looks like you are communicating with objects and callbacks within your own process. I would make the webapp and the business app communicating through this in order to get data. The webapp needn't manipulate the actual data and instead sends message to the Model layer (as described by the MVC pattern).

This ensures complete separation between controller/view (webapp) and model+persistence.

One side effect of this organization is that you can easily write other clients of your application, for example a CLI client or a RESTful API.

Floby
  • 2,306
  • 17
  • 15
  • In this scenario the external service fetching would still happen within the models. Instead of fat models, I'd get double models/controllers, one thin and one fat. I already have the app talking over a restful API and client-side MVC, so that would make it three layers of models/controllers... – Ricardo Tomasi Feb 07 '13 at 17:51
0

Are you trying to get id and somedata from url (post/:id/:somedata) ? to construct schema ?

Ideally one should use :

app.post('/reg', function(request, response){

console.log(request.body.name);
console.log(request.body.email);
...
}

which is when form is submitted on the 'reg' HTML form page, where you can set all the variables(name,email) in object. In app.post you can get the schema definition from the request itself without having to scan through the url to get variables.

If you still want to know how to get the variables from the url then do this in app.get:

vars=request.url.split('/');
//vars contains all the variables you have to use.
//use vars to create schema

After you get/create the schema directly pass it to the function / or iterate through the object elements calling that function.

user568109
  • 47,225
  • 17
  • 99
  • 123
  • That's not what's happening here. The url params would be `/post/123/comments` for example, but my question is totally unrelated to routing. – Ricardo Tomasi Feb 07 '13 at 17:54