基于node mvc和RESTful 模式的接口基础实现
-
MVC模式的主要思想是将业务逻辑按职责分离
控制器 (controller),一组行为的集合。
模型 (Model),数据相关的操作封装。
视图 (view),视图的渲染
这种分层模式的基本工作模式如下
- 路由解析
- 数据相关的操作
- 输出数据响应到客户端进行数据的渲染
根据这种基本的工作模式关系,我们可以实现自己的mvc接口(这里重点实现路由解析的相关过程)
-
mvc模式的接口实现
1,路由解析我们可以采用手工映射和自然映射两种方法实现,
手工映射可以通过一份路由表来保存映射关系,自然映射不存在这份路由表
手工映射实现案例
var routes = []; // 生成的router 所保存的位置
/*****路由配置文件,(可以用单独的模块配置然后require)*****/
var routes_config =[
{
path:"/user/get",
ctrl:(req,res)=>{
req.end("path=user/get")
}
},
{
path:"/user/post",
ctrl:(req,res)=>{
req.end("path=user/post")
}
}
];
// 设置路由方法
function setRoutes (path,action) {
routes.push([path,action])
}
routes_config.forEach((item,index)=>{
setRoutes(item.path,item.ctrl);
})
/****路由解析****/
function dealRoutes(req,res){
var pathname = url.parse(req.url).pathname;
for(var i=0;i
注意:上述的手工映射,没有考虑处理参数的情况,如果考虑处理参数的情况,可以用正则匹配来处理路由,也可以考虑修改 dealRoutes 方法中在url处理中解析参数
2,自然映射
手工映射相对自然映射更为灵活,如果项目较大,则会引发配置路由映射数量增多,从入口到ctrl需要查找对应的文件才能进行映射,为了方便映射,我们采用约定好的规则去实现路由,不需要每次都配置路由表。
自然映射实现的案例
```
var module = { // 可设置为控制器模块rquire引入
user:{
get:(req,res,args)=>{
// 解析处理args 参数
// 处理数据...(调用处理业务逻辑的方法)
req.end("user/get")//返回接口数据
},
post:(req,res,args)=>{
// 处理args 参数
// 处理数据...(调用处理业务逻辑的方法)
req.end("user/post")//返回接口数据
}
}
}
function dealRoutes(req,res) {
var pathname = url.parse(req.url).pathname;
var paths = pathname.split("/");
var ctrl = paths[1]||"login";
var action = paths[2] || "index";
var args = paths.slice(3);
var method;
try {
method = ctrl[action]
}catch(e){
return res500(req,res);
}
if(method){
method.apply(null,[req,res].concat(args))
}else{
res500(req,res);
}
}
```
-
RESTful 接口方式的实现
RESTful意为表现层状态转化,符合REST设计规范的,我们称为RESTful设计,它的设计哲学是将服务器提供的内容看做一个实体,并表现在URL上,
相当于一个URL代表一个实体资源,对这个实体资源的增删改查主要体现在请求方法上,而不是像以往一样体现在URL上。
- 资源的具体格式,根据请求头的accept字段进行判断
- 根据请求的method来匹配资源的操作方法
- 由匹配的方法分发对应的业务处理,响应返回的数据
RESTful接口实现
//可处理的数据格式配置
var acceptTypes ={
"application/json":true,
"application/xml":true,
"application/html":true
}
var setting ={
user:{
get:(req,res)=>{
if(acceptTypes[req.headers.accept]){
// 根据可允许的格式进行处理
res.write(`res:--${req.headers.accept}`)
}
res.end("user_get")
},
post:(req,res)=>{
res.end("user_post")
},
put:(req,res)=>{
res.end("user_put");
},
delete:(req,res)=>{
res.end("user_delete");
}
},
detail:{
get:(req,res)=>{
res.end("detail_get")
},
post:(req,res)=>{
res.end("detail_post")
},
put:(req,res)=>{
res.end("detail_put");
},
delete:(req,res)=>{
res.end("detail_delete");
}
}
}
//合并路由方法
var routes = {all:{
get:(req,res)=>{
res.end("all_get")
},
post:(req,res)=>{
res.end("all_post")
},
put:(req,res)=>{
res.end("all_put");
},
delete:(req,res)=>{
res.end("all_delete");
}
}
};
["get","post","delete","put"].forEach((method)=>{
routes[method]={};
for(let key in setting){
routes[method]["/"+key+"/"+method]=setting[key][method];
}
})
// 解析url,分发业务,返回数据
function handle (req,res) {
var pathname = url.parse(req.url).pathname;
var method = req.method.toLowerCase();
if(routes[method]){
var route = routes[method]
if(route[pathname]){
route[pathname](req,res);
}else{
routes.all[method](req,res)
}
}else if(routes.all[method]) {
routes.all[method](req,res)
}else{
handle404(req,res);
}
}
-
GraphQL接口
GraphQL 是由 Facebook 开发的,用于解决他们巨大、老旧的架构的数据请求问题。但是即使是比 Facebook 小很多的 app,也同样会碰上一些传统 REST API 的局限性问题。
这里暂时没有写到GraphQL接口的实现方案,后面自己将会补上这部分的内容。可以参考GraphQL官网
以上只是一个基础的mvc和RESTful模式的接口设计,当然我们的接口还需要经过一系列中间件的处理,比如处理cookies,session,auth等中间件的过滤,
一般我们会用到一些框架(express,koa2,egg)来开发项目,这些框架基本已经封装好了自己的路由和接口方法,上述可以用来了解一般框架接口实现的方法。
大家有好的方法,欢迎指导。