Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Node.js/Browser re-usable Entities

Gleam.js

for consistency of interfaces and data validation

Sydney, 19th September 2013

Nik Butenko

Imagine your usual CRUD Insert

Imagine your usual CRUD Insert

  1. Render form
  2. Listen to submit
  3. Validate input / Browser

Imagine your usual CRUD Insert

  1. Render form
  2. Listen to submit
  3. Validate input / Browser
  4. Send JSON to server
  5. Unserialize JSON
  6. Validate input / Server

Imagine your usual CRUD Insert

  1. Render form
  2. Listen to submit
  3. Validate input / Browser
  4. Send JSON to server
  5. Unserialize JSON
  6. Validate input / Server
  7. Normalize object / Server

Imagine your usual CRUD Insert

  1. Render form
  2. Listen to submit
  3. Validate input / Browser
  4. Send JSON to server
  5. Unserialize JSON
  6. Validate input / Server
  7. Normalize object / Server
  8. Save to DB
  9. ???
  10. PROFIT!

Form to add chat

 


Form to add chat

With HTML5 validation



Validate in Browser


function isValid($form) {
	var id = $form.find('[name=id]').val(),
			name = $form.find('[name=name]').val();
	return id.length && id.match('/^[a-z_-0-9]+/$') && name.length;

}
function onSubmit() {
	var $form = $(this);
	if (isValid($form)) {
		sendToServer($form);
	}
}
		

Validate on Server



function isValid(data) {
	return data.id 
			&& data.id.length 
			&& data.id.match('/^[a-z_-0-9]+/$') 
			&& data.name 
			&& data.name.length;

}
function chatAdd(req, res) {
	if (isValid(req.body)) {
		return saveToDb(
			normalize(req.body), 
			renderResponse(res)
		);
	}

	return renderResponse(res)({
		error: true, 
		message: "OMG!"
	});
}

		

Problem?

Pic by The Mary Sue www.themarysue.com

Problem?

  1. Write your validation 2 times (Server JS, Client JS)

Problem?

  1. Write your validation 2 times (Server JS, Client JS)
  2. Optionally one more time (HTML5)

Problem?

  1. Write your validation 2 times (Server JS, Client JS)
  2. Optionally one more time (HTML5)
  3. Check if you actually have necessary fields

Problem?

  1. Write your validation 2 times (Server JS, Client JS)
  2. Optionally one more time (HTML5)
  3. Check if you actually have necessary fields
  4. Normalize your objects before save to have consistency

Then later:

  1. Get data from db

Then later:

  1. Get data from db
  2. Make sure object has all necessary fields

Then later:

  1. Get data from db
  2. Make sure object has all necessary fields
  3. Send to client

Then later:

  1. Get data from db
  2. Make sure object has all necessary fields
  3. Send to client
  4. Check on client if you get correct objects from server

Then later:

  1. Get data from db
  2. Make sure object has all necessary fields
  3. Send to client
  4. Check on client if you get correct objects from server
  5. Check if you actually have all necessary fields

Then later:

  1. Get data from db
  2. Make sure object has all necessary fields
  3. Send to client
  4. Check on client if you get correct objects from server
  5. Check if you actually have all necessary fields
  6. And at last - SHOW THEM!

Yes, yes, I am paranoic about data consistency

Gleam to the rescue!

Pic by The Mary Sue www.themarysue.com

Add to your ExpressJS project


// Install Gleam first "npm install nkbt/gleam" 
//	or add as dependency - "gleam": "nkbt/gleam"
	
// ./app.js

// Require and configure Gleam
var gleam = require('gleam');
gleam.setRoot(path.join(__dirname, 'gleams'));

// [...] Do some ExpressJS configuration
			
// Add entity-serving middle-ware
// somewhere after static middleware
app.use(express.static(path.join(__dirname, 'public')));
app.use('/js/entity', gleam.serveEntity);
		

Write your Entity


// ./gleams/chat.js
'use strict';

var ChatEntity = {
	id: null,
	name: null,
	createdOn: null
};

// You need to export "Entity"
exports.Entity = ChatEntity;
		

Add validation


// ./gleams/chat.js

var ChatEntity = {

	//...

	validateId: function (value) {
		return !_.isEmpty(value) 
			&& _.isEqual(value, value.replace(/[^a-z_\-0-9]+/, ''));
	},

	validateName: function (value) {
		return !_.isEmpty(value);
	}

};
		

Add getters/setters


// ./gleams/chat.js

var ChatEntity = {

	//...

	getCreatedOn: function () {
		if (!this.createdOn) {
			var now = new Date();
			return now.getTime();
		}
		return this.createdOn;
	}

};
		

Run your app and try:

  1. /js/entity/chat.js
  2. /js/entity/from-json.js
  3. /js/entity/abstract.js
  4. /js/entity/inherit.js

Submit form


"use strict";

define(['entity/chat'], function (ChatEntity) {

	var chatEntity = new ChatEntity();
	try {
		chatEntity.set(getValues($form));
	} catch (error) {
		return alert(error.message);
	}
	// Submit to server

});
		

Restore JSON


"use strict";

define(['entity/from-json'], function (fromJson) {

	$.ajax({
		url: '', data: {/* some data */},
		dataType: 'text', // We need text!
		success: function (jsonString) {
			return fromJson(jsonString, function(error, entity) {
				console.log(entity);
			});
		}
	});

});
		

Save on server


"use strict";

var gleam = require('gleam');

function addChat(req, res) {
	try {
		var chatEntity = gleam.entity('chat', req.body);
	} catch (error) {
		// handle
	}
	// save chatEntity in DB
	db.save(chatEntity.get());
};
		

Get on server


"use strict";

var gleam = require('gleam');

function getChat(req, res) {
	db.get(req.param.id, function(json) {
		try {
			var chatEntity = gleam.fromJson(json);
		} catch (error) {
			// handle
		}
		res.json(chatEntity.get());
	})
};
		

Summary

  1. Write your entity once
  2. Write your validation, type casting, getters once
  3. Use it on a server
  4. Re-use it in your browser
  5. Always be sure your objects have all properties