was_framework v0.9.5
was_framework
Express-based framework used in the WAS course @UVersailles
Course page at http://swift.prism.uvsq.fr/
Install
npm install was_frameworkExample
var fmwk = require('was_framework');
var opts = {
default_handler: handler
};
// Create and configure application
var app = fmwk(opts);
function handler(req, res) {
res.send(200, 'Hello world');
}
// Start application on port 12345
app.start(12345);Recognized options
static_dirdirectory containing static content (must be an absolute path). Default:/path/to/script/static/.static_mountURL where static content is served. Default:/static.template_dirdirectory containing templates (must be an absolute path). Default:/path/to/script/templates/.default_handlerhandler to be executed when no other handler is found. Default:was_framework.not_found_handler.default_routeredirect all requests for '/' to this URL. Defaultnull.secretsecret used for cookies. Default:WAS.portport to listen to. Default8080.dbobject containing database configuration. See below. Defaultnull.
Example showing use of all options:
var fmwk = require('was_framework');
var opts = {
static_dir : __dirname + 'client',
static_mount : '/public',
template_dir : __dirname + 'views',
default_handler : handler,
default_route : '/index',
secret : 'my_secret',
port : 80
db : {
type: 'sqlite',
file: 'data.db'
}
};
var app = fmwk(opts);
app.f_routes.index = function(req, res) {
res.send('This is the default page');
}
app.f_routes.view = function(req, res) {
// my_client.js is in ./public
res.render('a_view.mu', {
title: 'This is a template',
script: '<script src="/public/my_client.js"></script>'
});
}
function handler(req, res) {
res.send(404, 'Not found');
}
app.start();All the options are added to the application's settings, so that you may get the using the .get:
var dir = app.get('static_dir');Starting the server
The .start method is used to start the application. It takes three arguments:
function start(port, db, callback)portis the port number to listen on.dbis an object as described in the Databases section. If both this object and thedboption is used, this one gets the precedence.callbackis a callback to be called after the server has started. It receives an optionalerrorargument if the server fails to start.
var fmwk = require('was_framework');
var opts = {
db: {
type: 'sqlite',
file: 'app.db'
}
}
var app = fmwk();
app.start(80, opts.db, function(err) {
console.log('Server started');
});Routing
was_framwork comes with a function name based router, mapping
URLs to functions with the least effort. Handlers are
added to the object app.f_routes.
var fmwk = require('was_framework');
var opts = {
// redirect all requests for / to /home
default_route: '/home';
}
var app = fmwk(opts);
app.f_routes.home = function(req, res) {
// this function handles requests for /home
};
app.f_routes.fee = function(req, res) {
// this function handles requests for /fee
};
// You can even nest functions inside objects
app.f_routes.foo = {
bar: function(req, res) {
// this function handles requests for /foo/bar
},
baz: function(req, res) {
// this function handles requests for /foo/baz
}
};
app.start();Besides the function name based router, was_framework supports also
the default router of express for finer control over
URLs and HTTP methods. Read the documentation of
express for more information.
Sending content
was_framework supports the usual .write and .end methods. More high-level functions to send content
to the user are available via express functions.
The .send method sends arbitrary content and sets the appropriate HTTP headers. To set the content type,
use the .type method.
app.f_routes.a_route = function(req, res) {
res.type('html');
res.send('<h1>Hello world!</h1>');
}The .json method compiles JavaScript objects to JSON and sends them with the appropraite HTTP headers.
Content type is automatically set
app.f_routes.xhr = function(req, res) {
var data = {
name : 'foo',
surname : 'bar',
adress : 'some avenue'
};
res.json(data);
}The .download method sends a file for download. The mime type is automaticalli guessed
app.f_routes.download = function(req, res) {
res.download('/path/to/file.png').
}Hogan.js templates
was_framework comes with built-in support for Mustache
templates using hogan.js.
Unless configured otherwise (see options), Mustache templates must be contained in a directory called
templates, and must have filename
ending in .mu or .mustache. Templates are compiled and sent
to the client at once using the .render.
app.f_routes.home = function(req, res) {
// Compile Mustache template and send to the user
res.render('about.mu', { title: 'My cool web app' });
}A feature unique to was_framework is the method .multiRender,
allowing to compile and send multiple templates. It makes a simpler alternative to partials. Here’s an example using
three templates, the compiled HTML is concatenated and sent to the
user.
app.f_routes.home = function(req, res) {
res.multiRender(['head.mu', 'body.mu', 'foot.mu'], { title: 'My cool web app' });
}Static file server
was_framework comes with built-in support for static files.
Create a directory named static inside your working directory: any file
contained in it will be available at the URL /static/filename. These paths can be configured, see options.
Redirections and other HTTP codes
URL redirections are performed by the .redirect method.
app.f_routes.rel_redirect = function(req, res) {
res.redirect('a/relative/url/');
};
app.f_routes.abs_redirect = function(req, res) {
res.redirect('/an/absoulte/url/');
}
app.f_routes.full_redirect = function(req, res) {
res.redirect('http://some.other.site/some/page');
}Other HTTP codes can be sent to the client, along with an arbitrary
message, using the .send method.
app.f_routes.error = function(req, res) {
res.send(500, '<h1>An unexpected error occured.</h1>');
}Cookies
Received cookies are parsed into the req.cookies object
app.f_routes.read_cookies = function(req, res) {
console.log(req.cookies.sessid);
}To set cookies, use the res.setCookie method, to clear the, use res.clearCookie
app.f_routes.set_cookie = function(req, res) {
res.setCookie('sessid', '1');
}
app.f_routes.clear_cookie = function(req, res) {
res.clearCookie('sessid');
}Databases
was_framework has builtin support for MySql and SQLite, based on the modules mysql
and node-sqlite-purejs. The
connection to the database is opened automatically before the server is
started. Use an SQLite database like this (if filename.db does not
exist, it is created automatically):
var fmwk = require('was_framework');
var opts = {
db: {
type: 'sqlite',
file: 'filename.db'
}
}
var app = fmwk(opts);
app.start(); // by default, listen on port 8080Use a MySql database like this:
var fmwk = require('was_framework');
var opts = {
db: {
type: 'mysql',
host: 'localhost',
user: 'root',
password: 'admin',
database: 'db'
}
}
var app = fmwk(opts);
app.start(); // by default, listen on port 8080Are also recognized all the options accepted by the modules mysql and node-sqlite-purejs.
After a successfull connection, an app.db object is created.
Independently of the driver, was_framework tries to provide an API as
consistent as possible with that of the mysql module. To
send an SQL query to the database, use the .query method of app.db, with the following signature
query(sql[, values[, callback]])Where sql is a string containing an SQL statement, values is an optional array of values to be replaced inside sql,
and callback is a function with signature callback(err, results) to be called upon completion or error.
The .query method supports automatic SQL esacping to help prevent SQL injections. A ? or ?? is replaced
by the corresponding value in values. ? is for escaping SQL values, while ?? is for escaping SQL identifierss.
In this example
app.db.query('SELECT ?? FROM table WHERE name=? AND town=?', ['adress', 'WAS', 'Versailles']);produces the SQL statement
SELECT `adress` FROM table WHERE name='WAS' AND town='Versailles'Always prefer automatic escaping. If you really want to do the
escaping manually, you can use the methods app.db.escape for
values app.db.escapeId for identifiers. An alternative is to use
app.db.format(sql, values), which returns a string with substitutions performed as in the .query method.
Here is a longer example.
app.f_routes.create_table = function(req, res) {
req.app.db.query('CREATE TABLE test (a TEXT, b TEXT)', function(err) {
if (err) console.log(err);
});
};
app.f_routes.select = function(req, res) {
// Prepared statement (use ?)
req.app.db.query('SELECT * FROM test WHERE a=? AND b=?',
[req.query.a, req.query.b],
function(err, results) {
if (err) {
console.log(err);
} else {
for (var i = 0; i < results.length; i++)
console.log(results[i]);
}
});
}Socket.io
was_framwork has builtion support for socket.io. To use it, simply pass the
option socket_io, and the socket object will be available at app.io.
var fmwk = require('was_framework');
var app = fmwk({
socket_io: true
})
app.f_routes.politesse = function(req, res) {
res.write('<script src="/socket.io/socket.io.js"></script>');
res.write('<script>');
res.write(' var socket = io.connect("http://localhost");');
res.write(' socket.on("merci", function (data) {');
res.write(' console.log(data);');
res.write(' socket.emit("de rien", { my: "Il n\'y a pas de quoi!" });');
res.write(' });');
res.write('</script>');
res.end();
}
app.io.sockets.on('connection', function(socket) {
socket.emit('merci', {greet: 'Merci beaucoup'});
socket.on('de rien', function(data) {
console.log(data);
});
});
app.start(12345)Alternatively, the http server for the application is available at app.http_server. You can use it to create
the socket like this.
var fmwk = require('was_framework');
var app = fmwk();
var io = require('socket.io').liste(app.http_server);