0.3.0 • Published 7 years ago

sails-formatter v0.3.0

Weekly downloads
3
License
MIT
Repository
github
Last release
7 years ago

Sails Formatter

Helps to specify how objects are displayed.

Motivation

I was thinking about modern MVCs. Nowadays these frameworks are mainly used for providing REST. That means that they're not MVC anymore, because there are no Views.

Why don't we introduce something like Formatters instead of Views? It is the same idea, but it will define how to build a JSON.

We use to have .toJSON() function, unfortunately it was very limited and deprecated now. Currently we have to define how to return an object in a Controller. It's usually very messy.

Not always you can print an object the same way as it's written in the model. You may need to load some additional data before print it, and frontend may also require different format of fields.

Forum is a good example. To print ForumModel you need to load and calculate how many related topics are inside, how many of them are new, etc.

That code to build one single forum object, can be quite big and messy, especially if you need to reuse it, or print it slightly different (full, teaser).

I think it make sense to move it out of controller, and organise somehow.

Installation

npm install sails-formatter --save

Files structure

All formatters must be placed under api/formatters/{Model}/{type}.js folder.

Usage

.one()

Formatter.one(object, model, type);

ArgumentTypeDetails
1objectObjectObject to be formatted.
2modelStringModel name of the object to be formatted.
3typeStringType of the formatter.
4dataObjectOptional data a formatter may require. Such as current user.

Returns

Type: Promise

Promise with formatted object.

Examples

var Formatter = require('sails-formatter');

User.findOne().then(function(user) {
  Formatter.one(user, 'user', 'full').then(console.log);
});

.many()

Formatter.many(objects, model, type);

ArgumentTypeDetails
1objectsArrayArray of objects which you want to format.
2modelStringModel name of the object to be formatted.
3typeStringType of the formatter.
4dataObjectOptional data a formatter may require. Such as current user.

Returns

Type: Promise

Promise with formatted objects.

Examples

var Formatter = require('sails-formatter');

User.find().then(function(users) {
  Formatter.many(users, 'user', 'teaser').then(console.log);
});

More examples

Let's create two formatters for User model.

All formatters must input an object to be formatter and return a promise.

// api/formatters/user/teaser.js
module.exports = function(object) {
  return Promise.resolve({
    id: object.id,
    name: object.name,
  });
};

You can reuse formatters inside a formatter:

// api/formatters/user/full.js
var Formatter = require('sails-formatter');

module.exports = function(object) {
  return Formatter.one(object, 'user', 'teaser').then(function(output) {
    output.first_name = object.firstName;
    output.last_name = object.lastName;
    
    return output; 
  });
};

Now, we can use them in the UserController:

// api/controllers/UserController.js
module.exports = {
  findOne: function (req, res) {
    var promise = User.findOne(req.param('id')).then(function(user) {
      return Formatter.one(user, 'user', 'full');
    });
    
    promise.then(res.ok).catch(res.badRequest);
  },
  
  find: function (req, res) {
    var promise = User.find().then(function(users) {
      return Formatter.many(users, 'user', 'full');
    });
    
    promise.then(res.ok).catch(res.badRequest);
  }
};

In case one formatter need some extra data to be build:

// api/controllers/TopicController.js
module.exports = {
  findOne: function (req, res) {
    var promise = Topic.findOne(req.param('id')).then(function(topic) {
      return Formatter.one(topic, 'topic', 'full', {
        currentUser: req.session && req.session.user
      });
    });
    
    promise.then(res.ok).catch(res.badRequest);
  }
};

// api/formatters/topic/full.js
var Formatter = require('sails-formatter');

module.exports = function(object, data) {
  var output = {
    id: object.id,
    name: object.name,
    body: object.body,
  };
  
  if (data.currentUser) {
    // That field need to know data.currentUser
    output.viewed_at = new Date().getTime();
  }

  return Promise.resolve(output);
};

Ideas

@sgress454 commented:

You could definitely create a hook that would load formatters from api/formatters and publish your hook to NPM.

Another idea of how to go about this sort of thing would be to create custom responses, so instead of using res.ok() you would do res.outputSomeModel(). You can put custom responses in api/responses and then call them from any controller.

0.3.0

7 years ago

0.2.0

7 years ago

0.1.0

7 years ago

0.0.1

7 years ago