Moa-api
项目地址:https://github.com/moajs/moa-api
目前是让开发可以快速的开发api类后端,开箱即用,可以最大程度发挥node express的威力
技术栈
- express
- mongoose
- bluebird
- res.api
Features
- 自动加载路由
- 支持mongodb配置
- 集成mongoosedao,快速写crud等dao接口
- 自带用户管理
- 使用jsonwebtoken做用户鉴权
- 支持migrate测试
- 支持mocha测试
- 默认集成res.api,便于写接口
- 集成supervisor,代码变动,自动重载
- gulp自动监控文件变动,跑测试
- gulp routes生成路由说明
开发流程
- 确定models内容,如果是已有库或已有模型,可以直接使用
- 编写接口文档
- 通过migrate来测试model里的方法(如果测试熟悉,可以直接写测试)
- 通过supertest来测试接口(R层)是否合法
- 通过mocha测试其他业务代码(C层、S层、M层)
RCSM分层思想
R = routes
路由层,和express的一样,唯一不一样的是只要是在app/routes下面的js都会自动挂载到路由上。
比如app/routes/user.js,它的访问地址是
比如app/routes/api/user.js,它的访问地址是
http://127.0.0.1:3000/api/user
然后路由里面的子地址,参照express路由写法即可。
典型用法是
var express = require('express');
var router = express.Router();
var $ = require('mount-controllers')(__dirname).users_controller;
/* GET users listing. */
router.get('/login', $.api.login);
router.get('/register', function(req, res, next) {
return res.api(200,{
a:'register'
});
});
module.exports = router;
从使用上来说,router.get('/login', $.api.login);
这个是最合理最常用的的。
但如果是逻辑非常简单的路由,随便写写也无妨
C = controllers
控制层,主要是负责接口处理结果如何返回,异常如何处理等逻辑控制,不处理具体逻辑
var users_service = require('mount-services')(__dirname).users_service;
// -- custom api
exports.api = {
login: function (req, res, next) {
// var user_id = req.api_user._id;
var is_valid = users_service.login_valid('sang', '000000');
if(is_valid == true){
return res.api(200,{
a:'login true'
});
}else{
return res.api(200,{
a:'login false '
});
}
}
}
说明:控制层的代码只会在R层里用到
S = services
业务逻辑层,通常业务比较负责才会用到业务逻辑层的,如果是单表能处理的,就没有必要使用services层了,所以S层通常是多个models操作的业务逻辑,为了逻辑清晰,以及防止C层膨胀,和耦合,S层很多时候是必要的。
说明:S层只会出现在C层代码里,是对多个models操作的封装。
M = models
模型层,也就是我们常说的dao层,即data access object,这里采用mongoose + mongoosedao完成model层建模
说明:M层可能出现在S层或C层,不允许出现在其他位置
auth权限
用户管理
鉴权接口
获取token作为以后的api授权凭证
获取请求api接口,可以通过header或参数授权
//检查post的信息或者url查询参数或者头信息
var token = req.body.token || req.query.token || req.headers['x-access-token'];
下面给出参数的测试方式
➜ moa-api git:(master) ✗ curl -d "username=sang&password=000000" http://127.0.0.1:3000/api/auth
{"success":true,"message":"Enjoy your token!","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NWMxOWZkZTNkYWMxZGViMDhjNDM4ODkiLCJ1c2VybmFtZSI6InNhbmciLCJwYXNzd29yZCI6IjAwMDAwMCIsImF2YXRhciI6IiIsInBob25lX251bWJlciI6IiIsImFkZHJlc3MiOiIiLCJfX3YiOjB9.ocfeQ_Kx00edNfbwDtpTrxXxotfOAo2a_zni9Ujsxwg"}%
即
token = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NWMxOWZkZTNkYWMxZGViMDhjNDM4ODkiLCJ1c2VybmFtZSI6InNhbmciLCJwYXNzd29yZCI6IjAwMDAwMCIsImF2YXRhciI6IiIsInBob25lX251bWJlciI6IiIsImFkZHJlc3MiOiIiLCJfX3YiOjB9.ocfeQ_Kx00edNfbwDtpTrxXxotfOAo2a_zni9Ujsxwg
R层鉴权示例
var express = require('express');
var router = express.Router();
var $middlewares = require('mount-middlewares')(__dirname);
var $ = require('mount-controllers')(__dirname).users_controller;
/* GET users listing. */
router.get('/login', $middlewares.check_api_token, $.api.login);
module.exports = router;
测试获取用户信息接口
curl http://127.0.0.1:3000/api/users?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NWMxOWZkZTNkYWMxZGViMDhjNDM4ODkiLCJ1c2VybmFtZSI6InNhbmciLCJwYXNzd29yZCI6IjAwMDAwMCIsImF2YXRhciI6IiIsInBob25lX251bWJlciI6IiIsImFkZHJlc3MiOiIiLCJfX3YiOjB9.ocfeQ_Kx00edNfbwDtpTrxXxotfOAo2a_zni9Ujsxwg
返回结果
// 20150805133902
// http://127.0.0.1:3000/api/users?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NWMxOWZkZTNkYWMxZGViMDhjNDM4ODkiLCJ1c2VybmFtZSI6InNhbmciLCJwYXNzd29yZCI6IjAwMDAwMCIsImF2YXRhciI6IiIsInBob25lX251bWJlciI6IiIsImFkZHJlc3MiOiIiLCJfX3YiOjB9.ocfeQ_Kx00edNfbwDtpTrxXxotfOAo2a_zni9Ujsxwg
{
"data": {
"users": [
{
"_id": "55c19fd43dac1deb08c43888",
"username": "12",
"password": "2",
"avatar": "23",
"phone_number": "23",
"address": "",
"__v": 0
},
{
"_id": "55c19fde3dac1deb08c43889",
"username": "sang",
"password": "000000",
"avatar": "",
"phone_number": "",
"address": "",
"__v": 0
}
]
},
"status": {
"code": 0,
"msg": "request success!"
}
}
migrate
当需要确定model里mongoose接口是否正确的时候,可以考虑创建一个migrate
node migrate/bill_in_account.js
如果是复杂的业务逻辑放到测试里。
task
list api routes
gulp routes
test
gulp
或者下面这样也行
➜ moa-api mocha test/controller
提醒:debug状态连接数据库:
mount routes_folder_path = /Users/sang/workspace/github/moa-api/app/routes
GET /users
[mongoose log] Successfully connected to: NaN
mongoose open success
set api header
GET /api/user/login 200 4.529 ms - 40
✓ respond with json
1 passing (33ms)
more
see http://nodeonly.com/2015/06/14/node-restful-api.html
全文完
欢迎关注我的公众号【node全栈】
联系我,更多交流
马克下,再研究。
@leapon 以后开源scaffold,配套的,哈哈
这个感觉好… 为什么用gulp? 看了几分钟 基本上是加了认证另外那个RSCM 太后端了 前端呢 感觉R层鉴权挺好的
我操 你这个有数据移民? 牛逼啊
@i5ting 貌似走 rails 的方向。大包大揽。
@tengrommel 这个是专门写api的,所以没有任何前端代码
gulp是nodejs里的一等公民,不需要利用的
@leapon 类似,但限于js的种种弊端。。。
你们程序设计思想好清晰,透彻。我做什么都乱糟糟的没个头,好痛苦。
@zh-h 那正好跟上,跟先进学习
架构很不错,我想盗用下,特别是鉴权那块,我仍还在用简单的cookie-session认证 自豪地采用 CNodeJS ionic
看到你r层的自动引用的方式,瞬间好大上啊,学习 自豪地采用 CNodeJS ionic
@huangzh123 还有大招没有放出来呢,哇哈哈
如果一个接口同时支持get/post呢
router.get_post('/sendemail', $middlewares.check_api_token, $.api.sendemail);
router.route('/')
.get($.list)
.post($.create);
➜ moa-api git:(master) mc
/Users/sang/workspace/moa/moa-console
Users/sang/workspace/moa/moa-console
提醒:debug状态连接数据库:
mongodb://127.0.0.1:27017/xbm-wechat-api
[2015-08-06 00:12:59.159] [INFO] [default] - undefined
[2015-08-06 00:12:59.161] [INFO] [default] - Welcome to the Moa console.
[2015-08-06 00:12:59.161] [INFO] [default] - undefined
Available Entity:
- Todo
- User
Moa> [mongoose log] Successfully connected to: NaN
mongoose open success
undefined
Moa> .list
Available Entity:
- Todo
- User
Moa> User.find({},function(err,doc){console.log(doc)})
undefined
Moa> [ { _id: 55c19fd43dac1deb08c43888,
username: '12',
password: '2',
avatar: '23',
phone_number: '23',
address: '',
__v: 0 },
{ _id: 55c19fde3dac1deb08c43889,
username: 'sang',
password: '000000',
avatar: '',
phone_number: '',
address: '',
__v: 0 } ]
undefined
Moa>
这个功能是不是也很爽?
@leapon 学习要系统才行,不能蜻蜓点水,做事要规划好。以前我都没有,吃苦
先顶再看,好好学学!
mark
一个功能的合集~
与这个系统的前端鉴权如何设计,能否示例一下?
获取token作为以后的api授权凭证
获取请求api接口,可以通过header或参数授权
//检查post的信息或者url查询参数或者头信息
var token = req.body.token || req.query.token || req.headers['x-access-token'];
下面给出参数的测试方式
➜ moa-api git:(master) ✗ curl -d "username=sang&password=000000" http://127.0.0.1:3000/api/auth
{"success":true,"message":"Enjoy your token!","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NWMxOWZkZTNkYWMxZGViMDhjNDM4ODkiLCJ1c2VybmFtZSI6InNhbmciLCJwYXNzd29yZCI6IjAwMDAwMCIsImF2YXRhciI6IiIsInBob25lX251bWJlciI6IiIsImFkZHJlc3MiOiIiLCJfX3YiOjB9.ocfeQ_Kx00edNfbwDtpTrxXxotfOAo2a_zni9Ujsxwg"}%
@SoaringTiger 这个主要适合于前后端分离的系统
比如angularjs,比如ionic类的
@i5ting 要的就是这个 👍
不错哦 Mark
mark
来自炫酷的 CNodeMD
mark
好东西
mark
马克下,稍后学习。
来自酷炫的 CNodeMD
mark
Controller,service,route涉及到user的文件都类似于…/…/node_modules/moa-plugin-user/app/routes/users.js,运行npm run start就报错为什么文件里面的内容是另一个文件的路径,全部注释后就可以正常运行了
@i5ting 难道意思是仿造路径的文件来编写方法吗