exctrl
Flexible controllers for express.js apps.
Easily load your controllers, no matter where they are, and mount their actions/routes to your app.
Installation
npm install exctrl
Usage
File app.js
:
var express = require('express'),
app = express(),
exctrl = require('exctrl');
// configuring express app...
exctrl.load(app, {pattern: __dirname + '/controllers/*.js'});
File /controllers/user.js
:
exports.create = function (req, res) {
// ...
res.send('user created');
};
exports.read = function (req, res) {
// ...
res.send('user read');
};
exports.update = function (req, res) {
// ...
res.send('user updated');
};
exports.del = function (req, res) {
// ...
res.send('user deleted');
};
exports.index = function (req, res) {
// ...
res.send('all users');
};
Results in:
POST /user
GET /user/:id
PUT /user/:id
DELETE /user/:id
GET /user
Generated URLs/routes
An URL generated by exctrl
has the format: [/<prefix>]/<controller name>[/<method name>][/<...>]
Detailed description of URL parts
<prefix>
An optional prefix to add to all mounted routes, and is provided via the options
hash, see the load
function below.
<controller name>
The main mount point for each controller and can be provided in three different ways:
- extracted from the controller file name, when using the
load
function (seeoptions
hash for options on how to extract the name) - as the
name
property of the controller if it's a string - as the first argument to the
mount
function, see below
<method name>
Magic method names / REST inspired
Some method names are considered "magic", in that way that it may imply both HTTP method and URL:
index
,list
orsearch
- http method:
GET
- url: mounted directly at the controller mount point (i.e. the
<method name>
is left empty), e.g."/user"
- http method:
create
- http method:
POST
- url: directly at controller mount point
- http method:
read
- http method:
GET
- params:
:id
- url:
"/<controller name>/:id"
- http method:
update
- http method:
PUT
- params:
:id
- url:
"/<controller name>/:id"
- http method:
del
- http method:
DELETE
- params:
:id
- url:
"/<controller name>/:id"
- http method:
Other method names
If a method name starts with a known HTTP method, i.e. get
, head
, post
, put
and delete
, it is mounted as that method in the provided express.js app, otherwise it's considered a get
method.
The HTTP method part from the method name is then cut off, and the remainings are dasherized (e.g. "getBestFriends" -> "best-friends"
) and added to the url.
Examples
- controller: "user", action: "getBestFriends" --> route:
GET /user/best-friends
- controller: "products", action: "get_top_sellers" --> route:
GET /products/top-sellers
- controller: "products", action: "postLike" --> route:
POST /products/like
- controller: "user", action: "get/:id/friends" --> route:
GET /user/:id/friends
<...>
is for..
What about middlewares or params you say? That's what the A controller action mustn't be just a function, e.g:
var basicController = {
name: 'basic',
getStuff: function (req, res) {
// ROUTE: GET /basic/stuff
}
};
For more advanced usage you can declare a controller action as an array (like AngularJS dependency injection syntax), e.g:
var middleware = function (req, res, next) { /* ... */ };
var advController = {
name: 'adv',
getStuff: [':type', middleware, ':anotherparam', 'chunk', function (req, res) {
// ROUTE: GET /adv/stuff/:type/:anotherparam/chunk
if (req.params.type === 'other') {
this.otherStuff(req, res); // Yes, `this` here is the actual controller
} else {
/* do something else */
}
}],
otherStuff: function (req, res) {
// ROUTE: GET /adv/other-stuff
res.send(/* other stuff */);
}
}
API
exctrl.load()
Params
- Function
app
- Your express.js app - Object
options
- A hash of options- String
pattern
- A glob pattern for finding controllers, e.g.
"controller/*.js"
or"**/*.ctrl.js"
- A glob pattern for finding controllers, e.g.
- RegExp
nameRegExp
- A regexp used for extracting controller name/mount point from the filename, e.g. with pattern
"**/*.ctrl.js"
a nameRegExp as/([^\/\\]+).ctrl.js$/
can be used to extract"user"
from/var/tmp/dir/user.ctrl.js
. The first match group will be used as extractor, and full path filename will be used when matching.
- A regexp used for extracting controller name/mount point from the filename, e.g. with pattern
- String
prefix
- If provided it will be prefixed to all mounted controller routes, e.g. with prefix
api
, controller nameuser
and action/methodget
the mounted route will be:GET /api/user
- If provided it will be prefixed to all mounted controller routes, e.g. with prefix
- String
Description
load() loads your controllers, and does so syncronously to make sure the routes are loaded at the time you want, to not interfere with other express.js configurations.
exctrl.bind()
Params
- Function
app
- Your express.js app
Description
bind() binds your app to exctrl
, so that you can skip first param to the load
function above.
Example
exctrl.bind(app)
.load(options);
exctrl.mount()
Params
- String
name
- The controller name, used as mount point - Object
controller
- A controller with methods as actions
Description
mount() is mainly used internally by exctrl
for mounting a controller at a mount point, but is available publicly for convenience, and will stay in the API.
Note if the controller object has a name
property with type String
the first parameter to this function can be omitted, and the controller.name
will be used as mount point instead.
Example
var name = 'user',
controller = {
index: function (req, res) {
res.send(/* all users */);
}
};
exctrl.bind(app)
.mount(name, controller);
// or
controller.name = name;
exctrl.bind(app)
.mount(controller);
Versioning
exctrl
uses Semantic Versioning as versioning model.
Contribution
Please feel free to contribute and send pull requests!
License
MIT, see ./LICENSE
file.