Combinando objetos con Lodash

Es cierto que los siguientes métodos proveen más características para combinar objetos, pero hoy vamos a cubrir el típico ejemplo de combinar “settings”:

let source = {
    title: 'Awesome',
    description: 'Awe-inspiring',
    derived: {
        awesomely: 'In a manner inspiring awe', 
        awesomeness: 'The quality of being awesome',
        awesomest: 'Superlative form of awesome: most awesome'
    }
};

let customizer = {
    title: undefined,
    description: 'Arousing awe through being nice',
    derived: {
        awesomely: 'Inspire kindness', 
        awesomeness: null,
        awesomest: undefined
    },
    synonyms: ['overwhelming', 'impressive'],
    antonym: 'boring',
};

_.assign(source, customizer)

assign

_.assign()

nota: _.extend es un alias de _.assign, por lo tanto funcionan igual.

_.merge(source, customizer)

merge

_.merge()

_.defaults(source, customizer)

defaults

_.defaults()

_.defaultsDeep(source, customizer)

defaultsDeep

_.defaultsDeep()

¿Ya había dicho que amo lodash?

_.get()

if (awesome && awesome.plugins && awesome.plugins.notification) {
    // Usa awesome.plugins.notification
}

Se puede simplificar usando la función “_.get()” de lodash:

if (_.get(awesome, 'plugins.notification')) {
    // Usa awesome.plugins.notification
}

lodash

Array of Objects

var users = [
    {username: 'josoroma', id:1, age: 38}, 
    {username: 'celine', id:2, age: 25},
    {username: 'isa', id:3, age: 21},
    {username: 'wifi', id:4, age: 21},
    {username: 'coco', id:5, age: 21}
];

_.findWhere

Encontrar la primera ocurrencia:

var findWhereUsers = _.findWhere(
    users,
    { 
        age: 21 
    }
);
{
    age: 21,
    id: 3,
    username: "isa"
}

_.where

Encontrar todas las ocurrencias:

var whereUsers = _.where(
    users,
    { age: 21 }
);
[
    {
        age: 21,
        id: 3,
        username: "isa"
    },
    {
        age: 21,
        id: 4,
        username: "wifi"
    },
    {
        age: 21,
        id: 5,
        username: "coco"
    }
]

Sí vale la pena aprender Typescript

Some people really like static type checking.

A simple vista parece que Typescript se siente como JavaScript pero con anotaciones lo cual es una ventaja “static typing”.

TypeScript Deep Dive

Typescript

Un lenguaje es “statically typed” si el tipo de una variable se conoce en su tiempo de compilación. La ventaja principal es que todos las verificaciones de tipos pueden ser realizadas por el compilador, lo que permite atrapar de manera temprana una gran cantidad de errores estúpidos.

Un lenguaje es “dynamically typed” si el tipo de una variable se interpreta en tiempo de ejecución, esto favorece al desarrollador ya que puede escribir código un poco más rápido, ya que no tiene que especificar el tipo cada vez.

La mayoría de los “scripting languages” tienen esta característica ya que no hay compilador para hacer “static typechecking” de todos modos, pero el desarrollador puede terminar buscando un error que se debe a la mala interpretación del tipo de una variable por parte del intérprete. Por suerte, la mayoría de los scripts tienden a ser pequeños, así que los errores no tienen tantos lugares para esconderse.

Por supuesto es posible desarrollar con ES6 y ES7, por ejemplo, usando Babel, lo interesante es que Typescript proporciona características similares a las de Babel, pero con el extra de la comprobación de tipos (es opcional).

Quickstart

The core concepts of Angular 2

Buenas excusas para aprender Angular 2

RTFM

Books

ng-book 2 Become a Ninja with Angular 2

Cheatsheet

Style GuideS

Awesome

Angular 2 Education

Learn Angular 2

Seeds, starters and boilerplates

AMD Modules and CommonJS Packages

Design Patterns

AMD Modules

/* -------------------------------------------------------------------------- */

/*
* AMD (Asynchronous Module Definition):
*
*   The module and dependencies can be asynchronously loaded. It helps to
*   removes the tight coupling between code and module identity.
*
*  JavaScript is single-threaded amd runs synchronous code executed in sequence:
*
*    All the time works on a synchronous code-flow executionn (in sequence).
*
*    Feel free to use Asynchronous code when performing expensive and
*    time-consuming operations.
*
*    We should always use XMLHttpRequest Asynchronously and update "the page"
*    when responses are available.
*
* Please read and enjoy:
*
*   https://github.com/amdjs/amdjs-api/wiki/AMD
*   
*   http://addyosmani.com/writing-modular-js
*/

/* -------------------------------------------------------------------------- */

/*
* My First Module.
*/
define('myFirstModule', [
  // Module Dependencies.
  'mySecondModule',
  'myThirdModule'
],
// Module definition function: Dependencies are mapped to Function Parameters.
function (mySecondModule, myThirdModule) {
  // Our Module Code Lives Here.
  var myFirstModule = {
    // Do stuff and Respond to requests.
    myResponse: function() {
      return '{"status": "success", "data": {"var": "val"}, "message": null}';
    };
  };
  // Returns a value that defines the Module Export.
  return myFirstModule;
});

/* -------------------------------------------------------------------------- */

/*
* Basic Example.
*/
define('myFirstModule', [
  'mySecondModule',
  'myThirdModule'
],
// Code lives here.
function (mySecondModule, myThirdModule) {
  return {
    myResponse: function(arg1, arg2) {
      return mySecondModule.yourResponse(
        myThirdModule.theirResponse(arg1, arg2)
      );
    };
  };
};
});

/* -------------------------------------------------------------------------- */

/*
* AMD Modules with jQuery.
*/
define('myjQeuryModule', [
  'js/jquery.js',
  'js/lodash.js'
],
// Here we map jQuery with $ and Lodash with _
function($ , _) {
  // Here we can use: https://jquery.com an d https://lodash.com
  // through the use of the parameters $ and _
  return {
    // What we return here can be used by other modules.
  };
});

/* -------------------------------------------------------------------------- */

/*
* Most Commonly Used Browser Module Loader: http://requirejs.org
*
* "yourModule" and "theirModule" are two external modules.
*
* The "exports" from this two modules loaded are passed as function
* arguments to the callback (yourModule, theirModule) so that they can
* similarly be accessed.
*/
require([
  'yourModule',
  'theirModule'
],
function (yourModule, theirModule) {
  // Rest of the Code Lives Here.
  yourModule.yourResponse();
  theirModule.theirResponse();
});

/* -------------------------------------------------------------------------- */

/*
* Dynamically-loaded Dependencies.
*/
define(function ( require ) {
  var isReady = false,
      myResponse;
  // Note the inline require within our module definition above.
  require([
    'yourModule',
    'theirModule'
  ],
  // Code lives here.
  function (yourModule, theirModule) {
    isReady = true;
    myResponse = yourModule.yourResponse() + theirModule.theirResponse();
  });
  // We can still return a module.
  return {
      isReady: isReady,
      myResponse: myResponse
  };
});

/* -------------------------------------------------------------------------- */

CommonJS Packages

/* -------------------------------------------------------------------------- */

/*
* CommonJS the Module Format Optimized For The Server.
*
* Is a Standard for Asynchronous Modules.
*
* The CommonJS module specifies a simple API for declaring server-side modules.
* It covers a set of concerns such as: io, filesystem, promises and more.
*
* Contains two primary parts:
*
*   A free variable named "exports" which contains the objects a module wishes
*   to make available to other modules.
*
*   A "require" function that modules can use to import the exports of other
*   modules.
*/

/* -------------------------------------------------------------------------- */

/*
* Package/library is a dependency we require.
*/
var library = require('package/library');

function myMethod() {
  return library.theirMethod();
}

// Exports/Exposes myMethod to other modules.
exports.myMethod = myMethod;

/* -------------------------------------------------------------------------- */

/*
* Most Commonly Used Server Module Loader: http://nodejs.org
*
* Node adapter for RequireJS: http://requirejs.org/docs/node.html
*
* Node.js is single-threaded amd runs synchronous code executed in sequence:
*
*   Sometimes have both asynchronous and synchronous versions of things:
*    - writeFile.
*    - writeFileSync.
*
*  "Node.js handles requests with a single thread concurrently by multiplexing
*   and sequencing all your JS logic in a single stream of execution which works
*   well for IO-bound workloads."
*
*   Always behave Asynchronous when I/O is involved or when in doubt.
*
* Please read and enjoy:
*
*   http://www.nodewiz.biz/your-doing-node-js-wrong-avoid-synchronous-code
*/

/* -------------------------------------------------------------------------- */

/*
* Basic consumption of exports.
*/
function messages() {
  this.success = function() {
    return '{"status": "success", "data": {"var": "val"}, "message": null}';
  }

  this.error = function() {
    return '{"status": "error", "data": null, "message": "System Message"}';
  }
}

// Exposes messages to other modules.
exports.messages = messages;

/* -------------------------------------------------------------------------- */

/*
* An application/module consuming 'messages'.
*/
var messages = require('./modules/messages').messages;

var res = new messages();

res.success();

/* -------------------------------------------------------------------------- */

Yeoman el generador de andamios

Yeoman es la herramienta para generar el andamio de una aplicación Web moderna. Ofrece un ecosistema de generadores. Un generador es, básicamente, un plugin que se puede correr con el comando “yo” para producir el andamio de un proyecto.

Yeoman Workflow

Herramientas

El flujo de trabajo Yeoman se compone de tres herramientas fundamentales que impulsan la mejora de la productividad y la satisfacción en la construcción de una aplicación web:

  • yo – La herramienta de andamios de Yeoman.
  • bower – La herramienta de gestión de paquetes.
  • grunt – La herramienta de construcción.

Instalación

Vamos a empezar instalando Yeoman y el “Ionic Framework Generator“:

npm install -g yo bower gulp grunt-cli compass ios-sim generator-ionic
mkdir yoionic && cd $_

yo ionic yoionic
grunt —force
grunt platform:add:ios

grunt emulate:ios --force
grunt serve --force

REST API con Sails – Adaptadores y MongoDB

Información de prueba

curl -is -X POST -d "username=josoroma&email=josoroma@example.com" http://localhost:1337/user

curl -is -X POST -d "username=celine&email=celine@example.com" http://localhost:1337/user

curl -is -X POST -d "username=uifi&email=uifi@example.com" http://localhost:1337/user/create

curl -is -X POST -d "username=coco&email=coco@example.com" http://localhost:1337/user/create
curl -is -X GET http://localhost:1337/user

curl -is http://localhost:1337/user

Generar REST API de ubicación

cd places

sails generate api location

sails lift

Listar

curl -is http://localhost:1337/location

Obtener un Registro desde el Browser

http://localhost:1337/user?where={"username":{"contains":"josoroma"}}

Por favor consulte: Find

Instalar MongoDB

brew install mongodb
lsof -iTCP -sTCP:LISTEN | grep mongo

mongod    337 user   11u  IPv4 0xfbda8d570c57142b      0t0  TCP localhost:27017 (LISTEN)
ps aux | grep '[m]ongo'

user          337   0.0  0.4  2718292  34692   ??  S     2:21PM   0:18.24 /usr/local/opt/mongodb/bin/mongod --config /usr/local/etc/mongod.conf
cat /usr/local/etc/mongod.conf

systemLog:
  destination: file
  path: /usr/local/var/log/mongodb/mongo.log
  logAppend: true
storage:
  dbPath: /usr/local/var/mongodb
net:
  bindIp: 127.0.0.1

Por favor consulte: Install MongoDB on OS-X

Instalar el adaptador MongoDB para nuestra aplicación

cd places

npm install -g sails-mongo --save

sails-mongo asocia/mapea el atributo lógico id con el _id de la capa física del Mongo id. En la versión actual de sails-mongo, no se debe ordenar por id.

Por favor consulte: sails-mongo

config/connections.js

mongo: {
  adapter: 'sails-mongo',
  host: '127.0.0.1',
  port: 27017,
  user: '',
  password: '',
  database: 'places'
},

Por favor consulte: Default MongoDB Port

lsof -iTCP -sTCP:LISTEN | egrep ':2701[7..9]'

mongod    337 user   11u  IPv4 0xfbda8c570c57143b      0t0  TCP localhost:27017 (LISTEN)

config/models.js

// Sails-Mongo Connection.
connection: 'mongo',

// Development Mode.
migrate: 'drop'

Lift

cd places

sails lift

Mongo desde la consola

mongo

Listar las Bases de Datos:

show dbs

admin   (empty)
local   0.078GB
places  0.078GB

Usar la Base de Datos llamada places:

use places

switched to db places

Listar las colecciones de la Base de Datos places:

show collections

location
system.indexes
user

Listar todos los documentos de la colección user:

db.user.find().pretty();

Por favor consulte:

REST API con Sails – Apps y CRUD

Crear una nueva App

sails generate new {pluralApplicationName}

sails new places

cd places

atom

Correr la aplicación Sails

Correr la aplicación Sails desde el directorio actual (si el archivo node_modules/sails existe, se utiliza en lugar del Sails instalado globalmente).

sails lift

Por favor consulte: sails lift

sails new {pluralApplicationName} es un alias que corre sails generate new {pluralApplicationName}.

Generar REST API de Usuario

cd {pluralApplicationName}

cd places

sails generate api {singularRestApiName}

sails generate api user

sails lift

Comprobar que el REST-API responde bien

curl -s http://localhost:1337/user

[]

Genera:

  • api/models/User.js
  • api/controllers/UserController.js

Configurar config/models.js

Por favor consulte: Migrate

  • sails.config.models.migrate=”alter”
  • migrate: ‘alter’

Esta opción controla si Sails intentará automáticamente reconstruir las Tablas/Colecciones/Conjuntos/etc. en el esquema de la Base de Datos.

En producción (NODE_ENV === “production”)

Sails utiliza siempre migrate: ‘safe’ para proteger el borrado accidental de datos. Sin embargo, durante el desarrollo, existen otras opciones interesantes:

  • safe – nunca auto-migra las bases de datos. Es como decir: Voy a hacerlo yo mismo (a mano).
  • alter – auto-migra, pero tratando de mantener los datos existentes (experimental).
  • drop – limpia todos los datos y reconstruye los modelos cada vez que se corre sails lift.

Generadores

Sails viene con varios generadores para ayudar a realizar los andamios de nuevas aplicaciones. También es permite que cualquiera pueda crear sus propios generadores para manejar tareas frecuentes, o ampliar la funcionalidad (por ejemplo, mediante la creación de un generador que da salida a archivos de vista de su lenguaje de plantillas favorito).

Por favor consulte: Generate

Configurar config/connections.js

Los adaptadores:

  • Son el intermediario entre nuestra aplicación Sails y algún tipo de almacenamiento (generalmente una base de datos).
  • Se configuran en el archivo config/connections.js de la aplicación. En este archivo se pueden crear diferentes “ajustes guardados” globales que se pueden mezclar y combinar desde los modelos.
  • Existen adaptadores en Sails para una variedad de bases de datos populares, tales como MySQL, Postgres y Mongo.

Por favor consulte: Blueprint API

Crear

curl -is -X POST -d "username=josoroma&email=josoroma@example.com" http://localhost:1337/user

curl -is -X POST -d "username=celine&email=celine@example.com" http://localhost:1337/user
HTTP/1.1 200 OK

{
  "username": "josoroma",
  "email": "josoroma@example.com",
  "createdAt": "2014-11-23T18:11:44.350Z",
  "updatedAt": "2014-11-23T18:11:44.350Z",
  "id": 1
}
{
  "username": "celine",
  "email": "celine@example.com",
  "createdAt": "2014-11-23T18:11:45.337Z",
  "updatedAt": "2014-11-23T18:11:45.337Z",
  "id": 2
}
curl -is -X POST -d "username=uifi&email=uifi@example.com" http://localhost:1337/user/create

curl -is -X POST -d "username=coco&email=coco@example.com" http://localhost:1337/user/create
 HTTP/1.1 200 OK

{
  "username": "uifi",
  "email": "uifi@example.com",
  "createdAt": "2014-11-23T18:12:14.281Z",
  "updatedAt": "2014-11-23T18:12:14.281Z",
  "id": 3
}
{
  "username": "coco",
  "email": "coco@example.com",
  "createdAt": "2014-11-23T18:12:15.118Z",
  "updatedAt": "2014-11-23T18:12:15.118Z",
  "id": 4
}

Listar

curl -is http://localhost:1337/user

curl -is http://localhost:1337/user/find

HTTP/1.1 200 OK

[
  {
    "username": "josoroma",
    "email": "josoroma@example.com",
    "createdAt": "2014-11-23T18:11:44.350Z",
    "updatedAt": "2014-11-23T18:11:44.350Z",
    "id": 1
  },
  {
    "username": "celine",
    "email": "celine@example.com",
    "createdAt": "2014-11-23T18:11:45.337Z",
    "updatedAt": "2014-11-23T18:11:45.337Z",
    "id": 2
  },
  {
    "username": "uifi",
    "email": "uifi@example.com",
    "createdAt": "2014-11-23T18:12:14.281Z",
    "updatedAt": "2014-11-23T18:12:14.281Z",
    "id": 3
  },
  {
    "username": "coco",
    "email": "coco@example.com",
    "createdAt": "2014-11-23T18:12:15.118Z",
    "updatedAt": "2014-11-23T18:12:15.118Z",
    "id": 4
  }
]

Un Registro

curl -is http://localhost:1337/user/find/1

curl -is -d "id=1" http://localhost:1337/user/find

curl -is -d "username=josoroma" http://localhost:1337/user/find

HTTP/1.1 200 OK

{
  "username": "josoroma",
  "email": "josoroma@example.com",
  "createdAt": "2014-11-23T18:11:44.350Z",
  "updatedAt": "2014-11-23T18:11:44.350Z",
  "id": 1
}

Actualizar

curl -is -X PATCH -d "username=josepablo"  http://localhost:1337/user/update/1

HTTP/1.1 200 OK

{
  "username": "josepablo",
  "email": "josoroma@example.com",
  "createdAt": "2014-11-23T18:11:44.350Z",
  "updatedAt": "2014-11-23T18:17:07.673Z",
  "id": 1
}
curl -is -X PUT -d "username=josoroma&email=example@josoroma.com"  http://localhost:1337/user/update/1

HTTP/1.1 200 OK

{
  "username": "josoroma",
  "email": "example@josoroma.com",
  "createdAt": "2014-11-23T18:11:44.350Z",
  "updatedAt": "2014-11-23T19:14:20.633Z",
  "id": 1
}

Borrar

curl -is -X DELETE http://localhost:1337/user/destroy/1

HTTP/1.1 200 OK

{
  "username": "josoroma",
  "email": "josoroma@example.com",
  "createdAt": "2014-11-23T18:11:44.350Z",
  "updatedAt": "2014-11-23T19:14:20.633Z",
  "id": 1
}
curl -is -X DELETE http://localhost:1337/user/destroy/1

HTTP/1.1 404 Not Found

No record found with the specified `id`.

Comprobar

curl -s http://localhost:1337/user

curl -is http://localhost:1337/user/find

HTTP/1.1 200 OK

[
  {
    "username": "celine",
    "email": "celine@example.com",
    "createdAt": "2014-11-23T18:11:45.337Z",
    "updatedAt": "2014-11-23T18:11:45.337Z",
    "id": 2
  },
  {
    "username": "uifi",
    "email": "uifi@example.com",
    "createdAt": "2014-11-23T18:12:14.281Z",
    "updatedAt": "2014-11-23T18:12:14.281Z",
    "id": 3
  },
  {
    "username": "coco",
    "email": "coco@example.com",
    "createdAt": "2014-11-23T18:12:15.118Z",
    "updatedAt": "2014-11-23T18:12:15.118Z",
    "id": 4
  }
]

Interacción agil con REST APIs

Postman

En Chrome es la herramienta más eficiente para probar, desarrollar y documentar una API. Agil para crear solicitudes complejas, volver atrás en el tiempo y ver los resultados de una manera amigable.

HTTPie

HTTPie es un cliente HTTP que se puede usar desde la línea de comandos, parece más fácil de usar que Curl.

curl -I http://reqr.es

HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Sun, 23 Nov 2014 04:44:08 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 10944
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Origin: *
ETag: W/"CenpWUsIvfcCYkB+PleqTA=="

Imprimir la respuesta en formato JSON amigable

curl -s http://reqr.es/api/users | xargs -0 node -e 
"console.log(JSON.stringify(JSON.parse(process.argv[1]), null, 2))"

npm install -g json

curl -s http://reqr.es/api/users | json
{
  "page": 1,
  "per_page": 3,
  "total": 12,
  "total_pages": 4,
  "data": [
    {
      "id": 1,
      "first_name": "george",
      "last_name": "bluth",
      "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"
    },
    {
      "id": 2,
      "first_name": "lucille",
      "last_name": "bluth",
      "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"
    },
    {
      "id": 3,
      "first_name": "oscar",
      "last_name": "bluth",
      "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg"
    }
  ]
}

Estilo YAML con color

npm install -g prettyjson
curl -s http://reqr.es/api/users | prettyjson

Mi favorito es underscore-cli

npm install -g underscore-cli
curl -s http://reqr.es/api/users | underscore print --color

GET

curl -is http://reqr.es/api/users
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Sun, 23 Nov 2014 05:10:18 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 446
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Origin: *
ETag: W/"1be-539742e1"

{"page":1,"per_page":3,"total":12,"total_pages":4,"data":[{"id":1,"first_name":"george","last_name":"bluth","avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"},{"id":2,"first_name":"lucille","last_name":"bluth","avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"},{"id":3,"first_name":"oscar","last_name":"bluth","avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg"}]}

POST

curl -is -X POST -d "name=Josoroma&job=Ninja" http://reqr.es/api/users
HTTP/1.1 201 Created
Server: nginx/1.6.2
Date: Sun, 23 Nov 2014 05:13:16 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 82
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Origin: *

{"name":"Josoroma","ob":"Ninja","id":"993","createdAt":"2014-11-23T05:13:16.017Z"}

PUT

curl -is -X PUT -d "name=Josoroma&job=Monk" http://reqr.es/api/users/2
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Sun, 23 Nov 2014 05:14:31 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 71
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Origin: *

{"name":"Josoroma","job":"Monk","updatedAt":"2014-11-23T05:14:31.618Z"}

DELETE

curl -is -X DELETE -d "name=Josoroma" http://reqr.es/api/users/2
HTTP/1.1 204 No Content
Server: nginx/1.6.2
Date: Sun, 23 Nov 2014 05:19:28 GMT
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Origin: *

Listar

curl -is http://jsonplaceholder.typicode.com/posts/1

Crear

curl -is -X POST -d "title=Heading&body=Content&userId=1" http://jsonplaceholder.typicode.com/posts

Actualizar

curl -is -X PUT -d "title=New Updated Heading&body=New Updated Content&userId=1" http://jsonplaceholder.typicode.com/posts/1
curl -is -X PATCH -d "title=New Patched Heading" http://jsonplaceholder.typicode.com/posts/1

Borrar

curl -is -X DELETE http://jsonplaceholder.typicode.com/posts/1

Filtrar

curl -s http://jsonplaceholder.typicode.com/posts?userId=1

Listar Recursos Anidados

curl -s http://jsonplaceholder.typicode.com/posts/1/comments

SailsJS Baby Steps

¿Qué es Sails?

Sails permite que sea fácil construir aplicaciones Node.js empresariales (estables y fiables) a la medida. Está diseñado para emular el patrón MVC de “frameworks” bien conocidos como Ruby on Rails, CakePHP y Django, pero soportando los requisitos de aplicaciones modernas: APIs basados en datos con una arquitectura orientada en servicios escalables. Especialmente efectivo para la construcción de chats y tableros de control en tiempo real, también es ideal para la construcción de juegos multi-jugador; pero se puede utilizar para cualquier proyecto o aplicación Web.

Introducción a Sails

Estructura MVC

  • Facilita modelos agnósticos de almacenamiento.
  • Controladores basados en un “blueprint”.
    Los controladores son pegados (“middleware”) con Express (para gestionar y hablar HTTP).
    Por ejemplo, una petición HTTP entra al servidor Web y Express provee toda la funcionalidad para responder un adecuada respuesta HTTP.
  • Las vistas del lado del servidor se presentan o dibujan basadas en el controlador. Se enfatizan en entregar un API, generalmente en formato JSON (entrega contra un URL), pero también soporta la generación de otros tipos de vistas basadas en controladores.

Nota: En la industria de la computación, el “middleware” es un término general para cualquier programación que sirve para “pegar entre sí” o mediar entre dos programas separados y, a menudo ya existentes.

Plantillas del lado del servidor

EJS limpia el HTML producido por JavaScript con el uso de plantillas del lado del cliente. Después de que EJS pone sus guantes en el código sucio, te vas a sentir más organizado y ordenado.

Pero también se puede extender a usar Handlebars o Jade.

Object-relational mapping (ORM Layer)

Waterline es un nuevo tipo de motor de almacenamiento y recuperación.

Adaptadores Agnósticos

Proporciona un API uniforme para acceder a cosas de diferentes tipos de bases de datos, protocolos y APIs de terceros. Esto significa que usted escribe el mismo código para obtener y almacenar cosas como datos de los usuarios, ya sea que vivan en Redis, MySQL, LDAP, MongoDB o Postgres. También se “pega” bien con APIs remotos como Twitter. Esto que permite que cualquier módulo en nuestra aplicación puede soportar diferentes adaptadores adicionales.

Modularidad

Waterline se esfuerza en heredar las mejores partes de ORMs conocidos como ActiveRecord, Hibernate, y Mongoose (“Object Modeling for Node.js”), pero con una nueva perspectiva y énfasis en la modularidad, capacidad de prueba, y la coherencia entre los adaptadores.

Nota: El mapeo objeto-relacional (ORM, O/RM, y O/R mapeo) en ciencias de la computación es una técnica de programación para la conversión de datos entre sistemas de tipos incompatibles en los lenguajes de programación orientados a objetos. Esto crea, en efecto, una “base de datos de objeto virtual” que se puede utilizar desde dentro del lenguaje de programación.

Policies

Siguen una estructura muy simple, son un “Express Middleware Callback”. Por convención corren antes de llegar a cualquier acción del controlador o a alguna acción específica del controlador.

Algunos de sus usos permiten:

  • Decorar datos de sesión.
  • Autenticación.

Para más información:

Soporte en tiempo real con Socket.io (req, res y next)

Socket.IO permite una comunicación en tiempo real y bidireccional basada en eventos. Funciona en todas las plataformas, navegadores Web o dispositivos, centrándose también en la fiabilidad y la velocidad.

  • Magia interna (traducción de rutas) todos responden a través de “sockets” o “http”.
  • Unifica la lógica del negocio.
  • Se extiende para agregar (broadcast events and join channels) res.broadcast() y req.join() para soportar un pubsub básico.

API Blueprints

Una vez que se crea un modelo con Sails, este provee de manera automática todos los “CRUD Blueprints” básicos, incluyendo búsqueda, ordenamiento y paginación. Son como “rutas mágicas” disponibles que no necesitan ser definidas.

Grunt-based Asset Pipeline

Sails usa Grunt para el manejo de tareas.

  • Auto-compila CSS Processors (LESS y Sass), CoffeScipt, etc.
  • Los assets son automáticamente combinados e inyectados en el DOM.
  • Soporta los modos de Desarrollo y Producción.

Sails es fácil de extender

Adaptadores

Los adaptadores Waterline soportan fuentes SQL, NoSQL y WebServices.

Generadores

Se pueden producir generadores a la medida para hacer scaffold en nuestra aplicación (CLI).

Hooks (todo es un hook)

El core de Sails es muy flexible y se puede extender de manera fácil mediante hooks.

Creating a Web App from scratch