huruji / blog

红日初升,其道大光:sun_with_face::house_with_garden:请star或watch,不要fork
https://juejin.im/user/5894886f2f301e00693a3e49/posts
158 stars 11 forks source link

resource-router-middleware项目源码阅读 #25

Open huruji opened 6 years ago

huruji commented 6 years ago

resource-router-middleware是一个提供restful API的Express中间件,由preact作者developit开发。 一个简单使用案例就是:

const resource = require('resource-router-middleware');
let users = [];
const huruji = {
    id:12,
    name: 'huruji',
    age: 12,
    sex: 'man'
};
const grey = {
    id: 13,
    name: 'grey',
    age: 12,
    sex: 'man'
};

users = [huruji, grey];

module.exports = resource({
   mergeParams: true,
   id: 'user',
   load: function(res,id, callback) {
       callback(null, huruji);
   },
   list: function(req, res) {
       res.json(users);
   },
   create: function(req, res) {
       var user = req.body;
       users.push(user);
       res.json(user);
   },
    read: function(req, res) {
       res.json(req.user);
    },
    update: function(req, res) {
       var id = req.params[this.id];
       for(var i = users.length;i--;) {
           if(users[i].id === id){
               users[i] = req.body;
               users[i].id = id;
               return res.status(204).send('Accepted');
           }
       }
       res.status(404).send('Not found');
    },
    delete: function(req, res) {
       var id = req.params[this.id];
       for(var i =users.length;i--;) {
           if(users[i].id===id) {
               users.splice(i,1);
               return res.status(200);
           }
       }
       res.status(404).send('Not found');
    }
});
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const userResource = require('./user');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/user',userResource);

app.listen(5000, function(err) {
    if(err) {
        return console.log(err);
    }
    console.log('server is listening port 5000')
});

可以学习的点主要是: 1、Express.Router可以提供一个对象参数

{
 mergeParams: 是否保留父级路由的req.params,且父子的req.params冲突时,优先使用子级的
caseSensitive:路由的路径是否大小写敏感,默认为false
 strict:是否启用严格模式,即/foo与/foo/区别对待
}

2、router.param的使用 3、取反运算,这个使用真的是相当巧妙 4、restful API的设计

var Router = require('express').Router;

var keyed = ['get', 'read', 'put', 'update', 'patch', 'modify', 'del', 'delete'],
    map = { index:'get', list:'get', read:'get', create:'post', update:'put', modify:'patch' };

module.exports = function ResourceRouter(route) {
    route.mergeParams = route.mergeParams ? true : false;
    // Express.Router可以提供一个对象参数
    /**
     * @param {
     * mergeParams: 是否保留父级路由的req.params,且父子的req.params冲突时,优先使用子级的
     * caseSensitive:路由的路径是否大小写敏感,默认为false
     * strict:是否启用严格模式,即/foo与/foo/区别对待
     * }
     */
    var router = Router({mergeParams: route.mergeParams}),
        key, fn, url;

    // 如果有中间件则装载中间价
    if (route.middleware) router.use(route.middleware);

    // router.param方法的回调函数的参数分别是req,res,next,params的值,params的key
    // 使用这个我们可以为路由的params找到数据之后直接定义在req对象中,供后续处理
    if (route.load) {
        router.param(route.id, function(req, res, next, id) {
            route.load(req, id, function(err, data) {
                if (err) return res.status(404).send(err);
                req[route.id] = data;
                next();
            });
        });
    }

    for (key in route) {
        // fn为对应的http method
        fn = map[key] || key;
        if (typeof router[fn]==='function') {
            // ~取反位运算,这个很有意思,三目运算符只有在~keyed.indexOf(key)为0时运算'/',取反值与原值相加为-1的原则知原值keyed.indexOf(key)为-1,也就是说
            // url = ~keyed.indexOf(key) ? ('/:'+route.id) : '/'与url = (keyed.indexOf(key) > -1) ? ('/:'+route.id) : '/';效果相同
            // 意义在于如果用户是使用keyed数组里的元素来定义键的,则使用('/:'+route.id)路由路径,否则使用'/'路由路径
            url = ~keyed.indexOf(key) ? ('/:'+route.id) : '/';
            console.log(key);
            console.log('url:' + url)
            router[fn](url, route[key]);
        }
    }

    return router;
};

module.exports.keyed = keyed;