Skip to content

Commit

Permalink
v0.1.0
Browse files Browse the repository at this point in the history
add sub dir support
fix alias bug
  • Loading branch information
zedgu committed Jul 17, 2014
1 parent 7738169 commit f9652fd
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 33 deletions.
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Surface

A tiny middleware of RESTful API for koa.

[![NPM][npm-status]][npm-status-url]

* Dependence on koa-router.
* Support JSON and XML format at the same time.
* Write a controller and get all route pattern you want.
Expand Down Expand Up @@ -61,8 +63,8 @@ Request the root of the app, for example: http://localhost:3000/, will be:
####Action Mapping
```
route http method function of ctrl
:resource/ get index
:resource/ post create
:resource get index
:resource post create
:resource/:id get get
:resource/:id put update
:resource/:id del del
Expand All @@ -84,7 +86,7 @@ Resource name will be the file name of the controller, if there is no alias set
},
'create': {
method: 'post',
path: '/'
path: ''
},
'get': {
method: 'get',
Expand All @@ -100,7 +102,7 @@ Resource name will be the file name of the controller, if there is no alias set
}
},
aliases: {
'index': '/'
'index': ''
}
}
```
Expand All @@ -119,9 +121,9 @@ exports.alias = 'name_you_want';
#####set routes for this controller
```js
exports.routes = {
create: {
method: 'post',
path: '/:id'
entry: {
method: 'get',
path: '/index'
}
};
```
Expand Down Expand Up @@ -153,3 +155,5 @@ exports.get = function *(next) {
[coveralls-url]: https://coveralls.io/r/zedgu/surface?branch=master
[david-image]: http://img.shields.io/david/zedgu/surface.svg?style=flat
[david-url]: https://david-dm.org/zedgu/surface
[npm-status]: https://nodei.co/npm/surface.png?downloads=true
[npm-status-url]: https://nodei.co/npm/surface/
4 changes: 4 additions & 0 deletions examples/simple/lib/controllers/users/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
exports.index = function *(next) {
this.body = 'in users';
yield next;
};
4 changes: 4 additions & 0 deletions examples/simple/lib/controllers/users/info/mail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
exports.index = function *(next) {
this.body = 'in /users/info';
yield next;
};
11 changes: 11 additions & 0 deletions examples/simple/lib/controllers/users/oauth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
exports.alias = 'auth';
exports.routes = {
entry: {
method: 'get',
path: '/index'
}
}
exports.entry = function *(next) {
this.body = 'in sub dir';
yield next;
};
44 changes: 30 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function Surface(app, option) {
}
},
aliases: {
'index': '/'
'index': ''
}
};
this._format = ['json', 'xml'];
Expand Down Expand Up @@ -116,17 +116,28 @@ surface.setting = function(option) {
};

surface.init = function() {
var ctrls = this._ctrls = this.load('ctrl')
, models = this._models = this.load('model')
var ctrls = this._ctrls = this.load(path.join(this.conf.root, '/', this.conf['ctrl']))
, models = this._models = this.load(path.join(this.conf.root, '/', this.conf['model']))
, C = this.ctrls = {}
, M = this.models = {}
, ctrl
, ctrlName
, basename
, alias
;

for (var file in ctrls) {
ctrl = C[file] = require(ctrls[file]);
ctrl.ctrlName = ctrl.alias || this.conf.aliases[file.toLowerCase()] || file.toLowerCase();
basename = path.basename(file.toLowerCase());

if (typeof ctrl.alias === 'string') {
alias = ctrl.alias;
} else if (typeof this.conf.aliases[basename] === 'string') {
alias = this.conf.aliases[basename];
} else {
alias = basename;
}
ctrl.ctrlName = file.toLowerCase().replace(new RegExp(basename + '$'), alias).replace(/\/$/, '');

if (models[file]) {
M[file] = ctrl.model = require(models[file]);
Expand Down Expand Up @@ -272,13 +283,16 @@ surface.register = function(app) {

/**
* to load files
* @param {String} components 'ctrl' or 'model'
* @return {Object} name:path
* @param {String} root root path
* @param {String} subPath sub dir path
* @param {Object} paths dictionary of the paths
* @return {Object} dictionary of the paths
* @api private
*/
surface.load = function(components) {
var dirPath = path.resolve(path.join(this.conf.root, '/', this.conf[components]))
, paths = {}
surface.load = function(root, subPath, paths) {
var dirPath = path.resolve(subPath || root)
, subPath = subPath ? path.basename(subPath) + '/' : ''
, paths = paths || {}
, files
;
try {
Expand All @@ -288,11 +302,13 @@ surface.load = function(components) {
}
files.forEach(function(file) {
file = path.join(dirPath, '/', file);
if (fs.statSync(file).isFile() && path.extname(file) == '.js') {
paths[path.basename(file, '.js')] = file;
} else {
// TODO
if (fs.statSync(file).isFile()) {
if (path.extname(file) === '.js') {
paths[file.replace(new RegExp('^' + path.resolve(root) + '/'), '').replace(/.js$/, '')] = file;
}
} else if (fs.statSync(file).isDirectory()) {
surface.load(root, file, paths);
}
});
return paths;
};
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "surface",
"version": "0.0.4",
"version": "0.1.0",
"description": "A tiny middleware of RESTful API for koa.",
"main": "index.js",
"scripts": {
Expand Down
53 changes: 44 additions & 9 deletions test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ var request = require('superagent')
;

var surface = Surface(app, {root: './examples/simple/lib'})
, localhost = 'http://127.0.0.1:3030'
, localhost = 'http://127.0.0.1:3030/'
;

app.listen(3030);
describe('Controllers', function(){
describe('index', function() {
describe('#index() GET /', function() {
it('should get res.body.data = "Hello World!"', function() {
request.get(localhost + '/')
request.get(localhost)
.end(function(res) {
res.status.should.eql(200, 'need 200');
res.body.should.have.properties({data: {Hello: 'World'}});
});
});
it('should be responsed in xml format and still get res.body.data = "Hello World!"', function() {
request.get(localhost + '/')
request.get(localhost)
.query({ format: 'xml' })
.accept('xml')
.parse(xml2jsParser)
Expand All @@ -31,7 +31,7 @@ describe('Controllers', function(){
});
});
it('should get res.status = 204', function() {
request.get(localhost + '/')
request.get(localhost)
.query({ empty: 'true'})
.end(function(res) {
res.status.should.eql(204, 'need 204');
Expand All @@ -43,14 +43,14 @@ describe('Controllers', function(){
var ctrlName = this.title;
describe('#index() GET /' + ctrlName, function() {
it('should get res.body.data = model.index()', function() {
request.get(localhost + '/' + ctrlName)
request.get(localhost + ctrlName)
.end(function(res) {
res.status.should.eql(200, 'need 200');
res.body.data.should.eql(surface.models.items.index());
});
});
it('should be responsed in xml format and still get res.body.data = model.index()', function() {
request.get(localhost + '/' + ctrlName)
request.get(localhost + ctrlName)
.query({ format: 'xml' })
.accept('xml')
.parse(xml2jsParser)
Expand All @@ -64,7 +64,7 @@ describe('Controllers', function(){
describe('#create() POST /' + ctrlName, function() {
describe('send post:true', function() {
it('should get res.body = "true"', function() {
request.post(localhost + '/' + ctrlName)
request.post(localhost + ctrlName)
.send({ post: 'true' })
.end(function(res) {
res.status.should.eql(200, 'need 200');
Expand All @@ -74,7 +74,7 @@ describe('Controllers', function(){
});
describe('send nothing', function() {
it('should get res.status = 415', function() {
request.post(localhost + '/' + ctrlName)
request.post(localhost + ctrlName)
.end(function(res) {
res.status.should.eql(415, 'need 415');
res.body.should.not.have.data;
Expand All @@ -84,13 +84,48 @@ describe('Controllers', function(){
});
describe('#get() GET /' + ctrlName + ':id', function() {
it('should get res.body.id = params.id', function() {
request.get(localhost + '/' + ctrlName + '/a')
request.get(localhost + ctrlName + '/a')
.end(function(res) {
res.body.data.should.eql('A', 'need A');
});
});
});
});
describe('users', function() {
var ctrlName = this.title;
describe('/', function() {
describe('#index()', function() {
it('should get res.body = "in users"', function() {
request.get(localhost + ctrlName)
.end(function(res) {
res.status.should.eql(200, 'need 200');
res.body.data.should.eql('in users');
});
});
});
describe('oauth', function() {
describe('#entry()', function() {
it('should get /auth/index res.body = "in sub dir"', function() {
request.get(localhost + ctrlName + '/auth/index')
.end(function(res) {
res.status.should.eql(200, 'need 200');
res.body.data.should.eql('in sub dir');
});
});
});
});
describe('info', function() {
describe('#index()', function() {
it('should get res.body = "in /users/info"', function() {
request.get(localhost + ctrlName + '/info/mail')
.end(function(res) {
res.body.data.should.eql('in /users/info');
});
});
});
});
});
});
describe('/*', function() {
describe('GET', function() {
it('should get 404 status', function() {
Expand Down
10 changes: 8 additions & 2 deletions test/surface.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ describe('Surface Testing', function(){
it('should be set with new root path "./examples/simple/lib"', function() {
surface.conf.root.should.eql("./examples/simple/lib");
});
it('should get items model of surface.models', function() {
surface.models.items.should.be.an.Object;
});
});
describe('#setting()', function() {
it('should return an object, no matter what type param you put', function() {
Expand Down Expand Up @@ -52,14 +55,17 @@ describe('Surface Testing', function(){
}
},
aliases: {
index: '/'
index: ''
}
});
});
});
describe('#load()', function() {
it('should load lib/controllers/* and return an object of the paths', function() {
it('should load dirpath which is not exist with no err and return an object {}', function() {
Surface(app, {root: 'a', ctrl: 'b'}).ctrls.should.eql({}, 'need {}');
});
it('should load files in sub dirs', function() {
Surface(app, {root: './examples/simple/lib'}).ctrls.should.have.properties(['index', 'items', 'users/oauth', 'users/info/mail']);
});
});
});

0 comments on commit f9652fd

Please sign in to comment.