[nodejs]为什么自己不为express写一个autoRoutes呢(二)?

根据上次的尝试,我觉得自动化的感觉还远远不够,首先是路由方面,虽然可以根据文件创建路由逻辑,但是非常重要的一点,路由的路径还是得手动填写。不仅是路由的路径,还有请求的办法,这点给人的感觉就是非常不智能了。

所以这次这个(二),就是要在原来的代码基础上做改进,要实现路由路径依据文件路径创建,请求方法根据文件名创建。而在文件里面,你只需要写两方面的内容,一个是实现路由逻辑,另一方面则是写好文档。

在这个文档方面我有三个想法,第一种想法是,在每个路由文件目录下加一个readme.md文件,然后把这个路由接口的文档写在里面,最后初始化加载路由文件的同时也读取这些readme.md的内容存储起来,然后写一个接口专门输出这些内容,再配合前端,自动构建起一个接口文档。

第二种想法是,在第一种想法的基础上,在注册路由的同时,同时也注册一个/api/doc/接口路由的接口,专门输出该路由的readme.md内容。简单讲,就是将初始化一次性读取变为分步读取吧。。。是不是有种懒加载的味道?23333.。。。

第三种想法,继承我之前的思路,直接把文档写在一个文件里面。

在这里,因为我懒(竟然这么恬不知耻的明说了?,就直接做第三种想法吧,想想每次写路由都要创建两个文件,想想都烦,而且还要用markdown写一堆相似的结构。。。这不智能对吧?渲染的工作啊,还是交给前端来,什么markdown和html都去他丫的。

好了,废话了那么多,接下来该干♂正事了。

实现

其实自动化构建文件路径路由,其实只需要一个小小的改动而已:

    var method='get';
    var route='/api/boo';
    var success=function(req,res){}
    app[method](route,success);

这里的app是express的实例,这个也是express注册路由的方法。很简单,只要把method换成遍历得到的路由文件名,比如”GET.js”的GET,然后再把它变成小写,这样就变成了:app.get(route,success)了,其余的POST|PUT|PATCH|DELET也是同理。

然后是route,这个你遍历文件夹的时候,文件路径是可得的,只要将这个文件路径拿过来,去掉有后缀名的文件名部分,就(可以吃了)可以用来当文件路径了。

不过,之前也说过,要实现RESTful式的API嘛(不懂RESTful的可以看一下阮一峰老师的介绍),有些接口需要实现后面路径自定义,比如我要根据一个id获取一篇文章的内容,首先文章的接口假如是GET /api/articles/,它的query是?aid=123456789,那么我希望能这样获取:GET /api/articles/aid/123456789或者直接GET /api/articles/123456789,但是,你用文件夹路径已经定死了,也不可能新建一个名字为*的文件夹(至少我不推荐这样做)。所以,这个是要考虑的问题。当然我相信这个小小的问题难不了大家。

我是这样做的,规定在文件名前面加个~号,比如/api/articles/~GET.js,那么该路径就会被解释为:/api/articles/*,即只要包含前面这部分的任何请求路径都由这个文件处理。这样就解决啦。什么?你想实现诸如/api/*/aid这种路由?额。。。这个。。。。等我想到方法再实现吧。。。

最后是success,这个不用说,肯定是路由文件的处理函数啦。

代码

整体代码也很简单,不过二十几行而已。。。

    var path=require('path');
    var fs=require('fs');
    var list=[];
    function readdir(dirPath, rname) {
        var arr = fs.readdirSync(dirPath);
        arr.forEach(function(item) {
            var next = path.join(dirPath, item);
            var api = rname + '/' + item;
            var stat = fs.statSync(next);
            if (stat.isDirectory()) {
                readdir(next, api);
            } else {
                if (/^[~]*(GET|POST|PUT|PATCH|DELET).js$/.test(item)) {
                    var method = item.replace(/(~|\.js)/g, '').toLowerCase();
                    var requirePath = next.replace('.js', '');
                    var route = api.replace(/\/[~]*(GET|POST|PUT|PATCH|DELET)\.js$/, '');
                    if (/~/g.test(item)) { //判断是否路由后面路径自定义
                        route += '/*';
                    }
                    var files = require(requirePath);
                    app[method](route, files.success);
                    files.info['route'] = route;
                    files.info['method'] = method;
                    files.info['index'] = list.length;
                    list.push(files.info);
                }
            }
        })
    }

很惭愧,这里做了一点点微小的工作:

  • 首先对比先前代码,这里不再直接把所有.js文件读进来了,只是读那些GET.jsPOST.js等等文件,这是为了方便。。。模块化?姑且称之为模块化吧,假如一个路由逻辑很复杂,处理起来很烦,或者全部处理方法堆在一个文件里面很不好看的时候,难免require大法好,为了相对路径读取方便,最好就是写在同级目录下,如:
        api
          ├─articles
         ...  ├─ ~GET.js
              ├─ POST.js
              └─ get.js
    

这个get.js肯定是不会被读进去的,所以可以放心的当做分模块的处理文件。

  • 其次,就是files.info['method'] = method;这句,这意味着,你在路由文件里面不需要再写method/route这两个info了。然后加了个index,其实这个并没啥卵用,就是为了让前端渲染的时候方便看第几个而已。

  • 最后,RESTful api不是还要求要把api的版本写在接口路径上吗?比如:
    api/v1/articles/aid/123456789,这个v1代表着版本号。这里也实现了,把原先那个用来记录文件require路径参数pathStr改为了可以在接口前添加版本或者其他信息的一个重命名作用的rname参数。比如:

    《[nodejs]为什么自己不为express写一个autoRoutes呢(二)?》 rname 第一个参数是放路由文件的文件夹,第二个参数是将所有路由前面都加上api/v1,然后请求路径就变成了:
    《[nodejs]为什么自己不为express写一个autoRoutes呢(二)?》 rname

  • 最后(刚才不是已经最后了么?),作为一个前端,接口文档,给别人看的东西一定要做得好:

    《[nodejs]为什么自己不为express写一个autoRoutes呢(二)?》 接口文档

啦啦,就这样~~鬼知道有没有(三)…..

    原文作者:CharTen
    原文地址: https://www.jianshu.com/p/311eb1574362
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞