scarab
v1.1.2
Published
Framework for building API-driven apps using MVC conventions
Downloads
42
Maintainers
Readme
Scarab, a minimal web framework
Scarab is a thin wrapper around Express, providing on structure, configuration and database abstraction. The structure is inspired by Rails and Sails.js, but with focus on keeping it simple. If the terms model, view, controller and route are new for you, please have a look at the documentation of Rails or Sails, as those do a better job on explaining them.
Motivation behind Scarab
- use Express and existing libraries
- provide structure
- keep it simple and readable (~500 lines of code).
Bootstrap the app
To start a server in the current directory:
// index.js
var scarab = require('scarab');
module.exports = scarab(__dirname);
Directory structure
By default Scarab looks for the following subdirectories:
- config
- init
- models
- controllers
- views
- policies
The directory names can be changed via config.paths
.
Configuration
Scarab imports and merges all files you put in the config/
subdirectory into one object (app.config
). In addition you can have subfolders for different environments (e.g. development, production), that override the settings put in the root config directory.
How you structure your settings (e.g. all in one file, split by purpose, etc.) is up to you. Just keep in mind that the files are loaded in alphabetical order, later files override earlier ones. Please see the samples
directory in the repository for a possible structure.
The setttings you configure here can be for Scarab, or for you own use (via app.config
).
The defaults for all the Scarab settings are in lib/defaults.js
.
Initialization
Each file put in init/
must export a function with one parameter app
. Those functions are run once after initializing the server.
Models
Scarab uses Databank for its models. Each model must export a DatabankObject
. Please refer to the Databank
documetation for further information.
By default the default database adapter specified in config.db.defaultAdapter
is used. A model can use a different adapter by adding an adapter
property.
Example:
// models/User.js
module.exports = function() {
this.adapter = 'redis';
this.schema = {
pkey: 'email'
};
this.prototype.beforeUpdate = function(props, callback) {
delete props.role;
callback(null, props);
};
};
AutoRoute
Each model automatically gets a REST endpoint. E.g. for the model user.js
you get api/users/
which lists all users and urls for adding, changing, deleting users. This can be disabled by setting config.autoRoute = false
or restricted using policies.
Autorouting uses the routing defined in config.resourceRouting
, and the controller defined in config.defaultControllerFactory
. By changing those, the automatic API can be customized according to your needs.
To change the behavior of a single Model, specify your own router for that model.
Default routes for autorouting (see Routes for more information):
'all /:controller/all': 'all',
'all /:controller/create/:key?': 'create',
'all /:controller/:key/update': 'update',
'all /:controller/:key/destroy': 'destroy',
'get /:controller': 'all',
'post /:controller': 'create',
'get /:controller/:key': 'find',
'put /:controller/:key': 'update',
'post /:controller/:key': 'update',
'delete /:controller/:key': 'destroy'
Controllers
A controller specifies behavior in one ore more actions. Each action is defined as an Express handler. By default, each controller extends/overrides the actions from the defaultController
(see AutoRoute). To prevent this behavior and having only the actions defined in the controller, add the property noDefaultActions: true
.
Example:
// controllers/TestController.js
var fs = require('fs');
var path = require('path');
var test = [
'first',
'second',
'third'
];
module.exports = {
noDefaultActions: true,
all: function(req, res, next) {
res.send(test);
},
find: function(req, res, next) {
var id = req.params.key;
if (test[id])
res.render('test.html.ejs', {title: test[id]});
else
res.send(404);
}
};
Routes
Routes are defined in config.routes
using the following syntax:
'<method> <path>': '<destination>'
<method>
can be:- one or more HTTP methods (e.g.
get
,post
,put
,delete
), comma separated all
: allow all methodsresource
: add all routes for a resource (config.resourceRouting
)static
: serves static files
- one or more HTTP methods (e.g.
<path>
: the url path. Supports everything Express supports: strings with variables or regular expressions (see Express routing).<destination>
can be:- a path starting with
/
: redirect to the path - an absolute or relative path (only for
static
) - a controller name (only for
resource
) - a string
<controller>.<action>
: callaction
oncontroller
. E.g.user.create
callscreate
in fileUserController.js
- an Object with properties
controller
andaction
if you like to be more verbose
- a path starting with
Example:
// config/routes.js
module.exports.routes = {
'get ^/admin$': '/admin/',
'get /auth/user': 'user.show',
'put,post /auth/login': 'user.login',
'get /auth/logout': 'user.logout',
'static /content': '../static/content'
};
Views
Templates in various formats. Scarab supports a lot of template languages via Consolidate. To use a template engine, you have to add it to config.viewEngines
. Templates can be rendered using res.render. Use template filenames including the extension (e.g. index.html.jade). This way the right template engine is used to render it.
Example:
res.render('test.html.ejs', {greeting: 'Hello world!'});
Policies
Policies apply additional logic (in the form of connect middleware) to certain paths / controllers / actions. The policies are defined in the directory policies/
and connected to controllers / actions via config.policies
.
Example:
// policies/admin.js
module.exports = function(req, res, next) {
if(req.user && req.user.role === 'admin') {
return next();
}
else {
return res.send(403);
}
};
// config/policies.js
module.exports.policies = {
User: {
create: 'admin',
update: 'admin',
destroy: 'admin'
},
'/api/*': 'authenticated'
};
Configuration
General
host
: Server Hostname (default:localhost
)port
: Server port (default:8080
)user
: User the server should run on (default:undefined
, meaning the current user)group
: Gropu the server should run on (default:undefined
, meaning the current user)logFile
: Logfile (default:undefined
, only output to stdout)modelGlobals
: if true, each model is added to the global namespace, otherwise just accessible byapp.models
(default:true
)
Paths
paths
: change standard subdirectories
module.exports.paths = {
config: 'config',
init: 'init',
models: 'models',
controllers: 'controllers',
views: 'views',
policies: 'policies'
};
Database
db.defaultAdapter
: name of the default adapterdb.<adaptername>.adapter
: name of the adapter (e.g. leveldb, redis)db.<adaptername>.settings
: settings to be passed to the adapter
Example:
// config/db.js
module.exports.db = {
defaultAdapter: 'redis',
redis: {
adapter: 'redis',
settings: {
host: '10.0.0.112',
database: 0,
checkIndices: true
}
}
};
Middleware
middleware
: a function which gets the app as a parameter. Define custom middleware here.
// config/middleware.js
var passport = require('passport');
module.exports.middleware = function(app) {
app.use(app.middleware.session({ secret: 'mysecret' }));
app.use(passport.initialize());
app.use(passport.session());
};
Autorouting
autoRoute
: automatically add resource routes for models (default:true
)autoRoutePath
: prefix for automatic routes (default:api
)defaultControllerFactory
: default controller actions (default:require('./default_controller_factory.js')
in the package)resourceRouting
: standard routes for resources and auto routes (default: seelib/defaults.js
)
View engines
viewEngines
: maps file extensions to view engines. For a list of supported view engines see: Consolidate
// config/views.js
module.exports.viewEngines = {
ejs: 'ejs',
jade: 'jade'
};
Routes
routes
: See chapter Routes above
Policies
policies
: See chapter Policies above
Asset compilation
Scarab does not bundle asset compilation functionality. The angular sample includes a Gruntfile that features file watching with live recompilation and automatic browser reload.
Usage:
- install Grunt:
npm install -g grunt-cli
- start server:
grunt server
- start server in production mode:
grunt server:dist
- build assets for production:
grunt build