Simple and intuitive MVC web framework for node.js
Simple and intuitive MVC web framework for node.js.
Agni is a web framework built on top of Express.
It adds a thin layer of abstraction which makes route definition and directory organization easier, without giving up the full power and flexibility of Express.
It does not include any database abstraction system, but leaves this choice to the developer.
Install agni globally: npm install agni -g.
Create an application called welcome: agni create welcome
Enter the newly created directory: cd welcome.
Install all dependencies: npm install.
Run the application: npm start.
Point your browser to localhost:3000.
If you see the welcome message, it works!
Agni is loosely based on the MVC development pattern.
The root application directory is app.
Inside app, you have the following directories:
controllers, models, and views, where you can store the modules belonging to the corresponding MVC components.
an unopinionated libraries directory.
config, which contains three files: config.js, with the application settings, middleware.js, where you can define middleware, and routes.yaml.
public, where you can put all your static resources like images, javascript files, style sheet and so on.
You can use the extensions .controller.js, .model.js and .lib.js for more readable file names.
Routes are defined in YAML format, in the app/config/routes.yaml file (or alternatively as standard javascript objects, but you should rename the file to route.js in that case).
Each route definition is composed of a label, one or more routes, and an action.
---
label:
route: verb /path
action: controller.action
Routes are composed of 2 segments, separated by a space:
Actions are composed of 2 segments, separated by a dot (.):
the first segment is a relative path, based on the app/controllers directory. This module can either export a constructor function or individual functions through the exports object.
the second segment can either be a prototype function or a function exported by the controller through the exports object.
Ex.:
---
foo:
route: get /foo
action: foo.index
// app/controllers/foo.controller.js
exports.index = function() {
this.render('foo');
}
Inside controllers, you can access the standard request and response objects as this.req as this.res, respectively.
For convenience, the following properties are also provided:
this.cookies (cookies)
this.session (session)
this.query (query string)
this.body (request body)
Inside controllers you also have a this.url method, which helps you build URLs from route labels and arguments.
url(label, arg1, arg2, ...) or url(label, argsArray)
Ex.:
firstPage:
route: /home
action: home.index
FooController.prototype.redirectToHome = function() {
this.res.redirect(this.url('firstPage', 'bar', 'baz'));// Redirects to /home/bar/baz
}
Rendering views is very easy. Inside a controller, execute:
this.render(viewName, locals, callback).
If you omit the view name, it will be the same as your controller module. For example, let's suppose you have a controller module called hello:
//File: app/controllers/hello.controller.js
exports.index = function() {
//This will render the view 'app/views/hello.jade'
this.render();
}
Inside views, you can use the url function to build URLs from route labels.
Ex.:
a(href='#{url("firstPage", "bar", "baz")}')
See the Controller methods paragraph for more details.
To access a model, you can use this.model(modelName) from any controller or library.
It will return the same object as require(__dirname + '../models/' + modelName).
Example:
//File: app/models/article.model.js
function ArticleModel() {
this.db = getMyDb();
}
ArticleModel.prototype.getArticle = function(id, callback) {
// Read article from DB
this.db.findArticleById(id, callback);
}
module.exports = ArticleModel;
And in the controller:
//File: app/controllers/article.controller.js
exports.read = function(id) {
var self = this;
var ArticleModel = this.model('article');
var articleModel = new ArticleModel();
articleModel.getArticle(id, function(err, data) {
if(! err) {
self.render('read_article', {articleData: data});
}
});
}
To access a library, you can use this.lib(libraryName) from any controller or library.
It will return the same object as require(__dirname + '../libraries/' + libraryName).
Example:
//File: app/libraries/string_helpers.js
exports.reverse = function(str) {
return str.split('').reverse().join('');
}
In the controller:
exports.read = function() {
var str = 'Hello';
var reversed = this.lib('string_helpers').reverse(str);
this.render({reversedHello: reversed});
}
In all controller, model and library functions you can access the Express app.settings object as this.settings.
Because Agni uses regular Connect middleware, you can pass errors to the next function, available inside controller functions as this.next. This will trigger a 500 Internal Server Error and send the error message to stderr. HTML error pages are in the views/errors directory.
Example:
//File: app/controllers/article.js
exports.read = function(id) {
var self = this;
this.model('article').getArticle(id, function(err, result) {
if(! err) {
self.res.json(result);
} else {
self.next(err);
}
});
}