# sails-formatter

> Helps to specify how objects are displayed.

Latest version **0.3.0** (published 2017-09-25) · MIT license · 0 weekly downloads

## Install

```sh
npm install sails-formatter
pnpm add sails-formatter
yarn add sails-formatter
bun add sails-formatter
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.3.0 |
| Published | 2017-09-25 |
| First published | 2017-03-22 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 1 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 1 |
| Author | Dmitry Demenchuk @mrded |
| Maintainers | mrded |

## Links

- npm: https://www.npmjs.com/package/sails-formatter
- Repository: https://github.com/mrded/sails-formatter
- Homepage: https://github.com/mrded/sails-formatter#readme
- Issues: https://github.com/mrded/sails-formatter/issues
- npm.io page: https://npm.io/package/sails-formatter

## Dependencies (1)

- [rootpath](https://npm.io/package/rootpath.md) ^0.1.2

## Recent versions

- 0.3.0 (latest) — 2017-09-25
- 0.2.0 — 2017-09-08
- 0.1.0 — 2017-05-04
- 0.0.1 — 2017-03-22

## README

# 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 **V**iews.

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()](http://sailsjs.com/documentation/reference/waterline-orm/records/to-json) 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);`

|   | Argument | Type     | Details                                                     |
|---|----------|----------|-------------------------------------------------------------|
| 1 | object   | `Object` | Object to be formatted.                                     |
| 2 | model    | `String` | Model name of the object to be formatted.                   |
| 3 | type     | `String` | Type of the formatter.                                      |
| 4 | data     | `Object` | Optional data a formatter may require. Such as current user. |

#### Returns
**Type:** `Promise`

Promise with formatted object.

#### Examples

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

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

---

### .many()
`Formatter.many(objects, model, type);`

|   | Argument | Type     | Details                                                     |
|---|----------|----------|-------------------------------------------------------------|
| 1 | objects  | `Array`  | Array of objects which you want to format.                  |
| 2 | model    | `String` | Model name of the object to be formatted.                   |
| 3 | type     | `String` | Type of the formatter.                                      |
| 4 | data     | `Object` | Optional data a formatter may require. Such as current user. |

#### Returns
**Type:** `Promise`

Promise with formatted objects.

#### Examples

```javascript
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](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise).

```javascript
// 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:
```javascript
// 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`:

```javascript
// 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:

```javascript
// 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](https://github.com/sgress454) [commented](https://github.com/balderdashy/sails/issues/4049#issuecomment-288526987):
> 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`](http://sailsjs.com/documentation/concepts/custom-responses/adding-a-custom-response) and then call them from any controller.

---
_Source: https://npm.io/package/sails-formatter · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
