Intro to Sail.js

Preview:

DESCRIPTION

Sails.js is a realtime MVC framework for Node.js that is inspired by some of the best ideas behind Ruby on Rails and realtime frameworks like Meteor.js. In this presentation I'll overview getting started with Sails.js, its architecture and features, as well as some advice on place to look at when you are getting started. Learn a brand new way to think about web application development with Node.js!

Citation preview

http://www.meetup.com/Pittsburgh-Node-js/

NICHOLAS MCCLAYUX Developer

@nickmcclay

MEET YOUR NEIGHBOR

Framework Overview

SAILS HIGHLIGHTS• Robust Node.js MVC web server framework !

• Railsy features - scaffolding, DB agnostic ORM !

• Automatically generated RESTful JSON API !

• Out-of-the-box real-time socket.io integration !

• Role based access policies and ACL !

• JS/CSS asset bundling and minification (Grunt)

QUICK NOTE:Convention > Configuration = Magic

WHAT IS A SINGLE PAGE APPLICATION?

TRADITIONAL WEB APPLICATION

One Kitten Please!

HTTP Request

http://www.cutekitties.com/kitten/1

Response

HTMLJavaScript

CSS

TADA! WEB PAGE!

SINGLE PAGE APPLICATION

One Kitten Please!

HTTP Request

http://www.cutekitties.com#/kitten/1

Response

HTMLJavaScript

CSS

Application

GET /kitten/1

A JAX Request

/kitten/1?format=json

Response

JSON

[{ "_id" : "abc124efg345", "lives" : 9, "curiousity" : "massive", "cuteness" : 9999, "eyes" : "blue", "fur" : "yellow"}]

TADA! WEB APP!

Heading out to sea

SAILS VERSIONS

V0.9 V0.10

• Current NPM default • Reliable starting place • What I’ll be demoing

in this presentation

• beta version (RC3) • Significant Refactors • API changes • Associations • Here be dragons…

https://github.com/balderdashy/sails-docs/blob/master/Migration-Guide.md

Coming

V0.10 Soon

DOCUMENTATION SOURCES

https://github.com/balderdashy/sails-docs/tree/0.10Coming

V0.10 Soon

http://sailsjs.org/#!documentation

Official Website Documentation

GitHub Documentation Repo

CREATE A NEW SAILS PROJECThttp://sailsjs.org/#!getStarted

0.10.0 NPM INSTALL WEIRDNESS

If you encounter this, try:

npm install -g

SAILS CLI BASICS

sails lift --dev --prod

sails new <appName> --linker

sails version

--verbose

Make a new app Turn on asset linking

Run App Set Env Config Display all logs

Display Sails.js Version

SAILS SCAFFOLDING

sails generate (type) <id>

Generate Scaffolding

model, controller, default is both

sails generate (type) <id>

model, controller, api, blog, user, whatever you want!

Pluggable Generators for ScaffoldingComing

V0.10 Soon

MODELSvar Person = { schema : true, attributes: { firstName: 'string', lastName: 'string', password : { type : 'string', required : true, notEmpty : true }, age : { type: 'integer', max: 150, required: true }, birthDate: 'date', phoneNumber: { type: 'string', defaultsTo: '111-222-3333' }, emailAddress: { type: 'email', // Email type will get validated by the ORM required: true } }}; model.exports = Person;

(Waterline Collection)api/models

BEYOND ATTRIBUTES// Define a custom instance methodfullName: function() { return this.firstName + ' ' + this.lastName; }, // Lifecycle CallbacksbeforeCreate: function(values, next) { bcrypt.hash(values.password, 10, function(err, hash) { if(err) return next(err); values.password = hash; next(); });}, // Override toJSON instance method// to remove phoneNumber valuetoJSON: function() { var obj = this.toObject(); delete obj.password; return obj; }

ORM - WATERLINEhttps://github.com/balderdashy/waterline

• ActiveRecord, Hibernate, and Mongoose

• emphasis on modularity, testability, and consistency across adapters

• Waterline Adapter -> DB Query • Custom Adapter methods

ASSOCIATIONSComing

V0.10 SoonAssociate models across different data stores

var Blog = { attributes : { title : 'string', body : 'string', author : { model : 'person' } }};

• One way • One-to-One • One-to-Many • Many-to-Many

Blog.find({title:'Sails.js Presentation'}).populate('author').exec(console.log);

Relationship TypesDefining Association

Full Sail Ahead!

RESOURCEFUL ROUTING

/:controller/find/:id? /:controller/create /:controller/update/:id /:controller/destroy/:id

get /:controller/:id? post /:controller put /:controller/:id delete /:controller/:id

!To disable set the ‘rest’ flag to false in config/controllers.js

To disable set the ‘shortcuts’ flag to false in config/controllers.js,

CRUD Routes

REST Routes

FREE

FREE

CONTROLLERSapi/controllers

var ChickenController = { // Peck the chicken specified by id (subtract 50 HP) peck: function (req,res) { Chicken.find(req.param('id')).exec(function (err, chicken) { if (err) return res.send(err,500); if (!chicken) return res.send("No other chicken with that id exists!", 404); if (chicken.hp <= 0) return res.send("The other chicken is already dead!", 403); chicken.hp -= 50; // Subtract 50 HP from the chicken chicken.save(function (err) { // Persist the change if (err) return res.send(err,500); // Report back with the new state of the chicken res.json(chicken); }); }); }}; module.exports = ChickenController;

SOCKET.IO

// all controller routes return valid responsessocket.get('/todo/count', function(results) { console.log(results) });// create a new itemsocket.post('/todo', {"title" : "this is from sockets"}, function(err,results) { console.log(err,results) });// all valid ways to update with websocketssocket.put('/todo', {'id' : 1, 'title' : "updated1"}, function(results) { console.log(results) });socket.put('/todo/1', {'title' : "updated2"}, function(results) { console.log(results) });socket.get('/todo/update/1', {'title' : "updated3"}, function(results) { console.log(results) });// all valid ways to delete with websocketssocket.delete('/todo', {'id' : 1}, function(results) { console.log(results) });socket.delete('/todo/1', function(results) { console.log(results) });socket.get('/todo/delete/21',function(results) { console.log(results)});// listen for messagessocket.on('message', function(message) { console.log(message) });// listen for messages from a specific controllersocket.on('todo',function(message) { console.log(message) }); Coming

V0.10 Soon

http://socket.io/

POLICIESapi/policies/isAuthenticated.js

module.exports = function(req, res, next) { // User is allowed, proceed to the next policy, // or if this is the last policy, the controller if (req.session.authorized == true) { return next(); } // User is not allowed // (default res.forbidden() behavior can be overridden in `config/403.js`) return res.forbidden('You are not permitted to perform this action.');};

config/policies.jsmodule.exports.policies = { // Default policy for all controllers and actions // (`true` allows public access) '*': true, // Policies for /Foo/* routes FooController: { "*" : true, 'update' : 'isAuthenticated', 'destroy' : ['isAuthenticated','isOwner'] }};

ASSET MANAGEMENT

sails new <appName> --linker

Enabling Asset Linking

Place Assets in between special linker flags

assets/linker/

GET STARTED BUILDING

https://github.com/cgmartin/sailsjs-angularjs-bootstrap-example

https://www.npmjs.org/package/generator-sails

http://irlnathan.github.io/sailscasts/

THANKS!

@nickmcclay

Recommended