文章导读:
要理解什么是RESTful API我们可以先看一下什么是RESTful架构。
REST是Representational State Transfer的缩写,我们可以理解为它的含义是“表现层状态转化”,wikipedia是这样说的:“an architectural style that abstracts the architectural elements within a distributed hypermedia system”,这就是REST互联网软件的架构原则。
我们可以说如果一个架构符合REST原则,就称它为RESTful架构。
那么回到我们的RESTful api,我们为了有一种统一的机制,方便不同的前端设备与后端进行通信于是便有了 RESTful API这一套目前比较成熟的互联网应用程序的API设计理论。那么我们为了设计一个合理,好用的api,需要做些什么呢?简单的说大致需要做到以下几点:
1 1. api与用户的通信协议总是使用HTTPs 2 2. 我们尽量将API部署在专用域名下:https://api.example.com 3 3. url中有标示api版本号的字段:https://api.example.com/v1/ 4 4. 路径带有明确的含义:https://api.example.com/v1/animals 5 5. 明确资源的具体操作类型,使用相应的HTTP方法:GET/POST/PUT/DELETE/PATCH 6 6. api中提供过滤信息的参数:?page=2&per_page=100:指定第几页,以及每页的记录数 7 7. 请求api后服务器需要返回明确的状态码,如果出错,带有错误处理
其实我们可以简单的理解为RESTful API就是更加规范的API。
下面我们就可以开始基于Nodejs的express和koa来实现一些例子理解下RESTful API。
我们先通过一个简单些的只get获取数据库中数据的例子开始:
2.1.1 准备工作:
确认我们已经安装了nodejs express;
install mongodb数据库mac ;
2.1.2 先开始最简单的例子:
目录结构,data是数据库相关的目录,我们可以先忽略掉:
确保我们的package.json文件中有mongodb等依赖:
1 { 2 "name":"node-api", 3 "main":"server.js", 4 "dependencies":{ 5 "express":"~4.0.0", 6 "mongoose":"~3.6.13", 7 "body-parser":"~1.0.1", 8 "morgan":"~1.5.3", 9 "mongodb":"~2.0.33", 10 "monk":"~1.0.1" 11 } 12 }View Code
在server.js中定义简单的路由和进行数据库操作:
1 var express = require('express'); 2 var app = express(); 3 var bodyParser = require('body-parser'); 4 var path = require('path'); 5 //database 6 var mongo = require('mongodb'); 7 var monk = require('monk'); 8 var db = monk('localhost:27017/restdata'); 9 10 //app.use()里面没有函数 11 app.use(bodyParser.urlencoded({ extended : true})); 12 app.use(bodyParser.json()); 13 14 app.use(express.static(__dirname+'/public')); 15 16 var collectorder = db.get('orderlist'); 17 var collectuser = db.get('userlist'); 18 19 20 app.get('/orders',function(req,res){ 21 collectorder.find({},{limit:20},function(err,orders){ 22 res.json(orders); 23 }); 24 }); 25 app.get('/users',function(req,res){ 26 collectuser.find({},{},function(err,users){ 27 res.json(users); 28 }); 29 }); 30 31 app.get('/users/:name',function(req,res){ 32 //var collection = db.get(req.params.name); 33 //console.log(req.params.name); 34 collectuser.find({name:req.params.name},{},function(err,docs){ 35 res.json(docs); 36 }); 37 }); 38 39 //客户端通过请求adduser接口post数据进入数据库 40 // app.post('/adduser',function(req,res){ 41 // var db = req.db; 42 // collectuser.insert(req.body,function(err,result){ 43 // res.send( 44 // (err == null) ? {msg:''}:{msg:err} 45 // ); 46 // }); 47 // }); 48 49 50 51 52 app.listen(3000);View Code
数据库操作:
1 mongod --dbpath c:/node/nodetest2/data (项目中data目标路径)
新开一个控制台窗口运行:
1 mongo 2 use nodetest2(意义上的数据库名称) 3 db.userlist.insert({'username' : 'test1','email' : 'test1@test.com','fullname' : 'Bob Smith','age' : 27,'location' : 'San Francisco','gender' : 'Male'}) 4 我们可以查看[monk] 的api,查看数据库的操作方法
如果没有什么问题的话,两个控制台窗口应该是这样的:
运行实例:
1 node server.js
访问url就可以看到我们获取到了的数据:
[ 查看项目源码 ]
实际上,我们刚才的例子并不算是一个完整的express的项目。我们只是用到了其中的几个API。我们通过express-generator生成的express项目的脚手架应该是这个样子的:
我们可以看到入口的app.js文件,以及控制路由的routes和控制显示的views文件夹,里面存放了jade模板的文件。很好地组织了项目的目录。
可以从express官方github开始,快速上手express:[ expressjs ].
这里说的数据交互的例子,有个非常详细易懂的教程:[ CREATING A SIMPLE RESTFUL WEB APP WITH NODE.JS, EXPRESS, AND MONGODB ]
然而也可以直接获取我仓库中的项目源代码:[ RESTful API datachange ]
3.1 简单get数据
同样,koa版本我们也从最简单的实例开始。
1.目录结构,同样,我们也先忽略跟数据库相关的data文件夹:
2.确保我们的package.json文件中依赖了koa koa-route mongoose 和monk等:
1 { 2 "name": "koarestapi", 3 "version": "0.0.1", 4 "description": "", 5 "main": "app.js", 6 "dependencies": { 7 "co-body": "~0.0.1", 8 "co-monk": "~0.0.1", 9 "koa": "~0.1.2", 10 "koa-route": "~1.0.2", 11 "koa-router": "~2.2.0", 12 "kongo": "~0.0.3", 13 "mongoose": "~3.8.3", 14 "monk": "~0.7.1" 15 }, 16 "author": "yixuan" 17 }View Code
3.同样在app.js中定义koa版本的路由和简单的数据库操作:
1 var koa = require('koa'); 2 var route = require('koa-route'); 3 var app = module.exports = koa(); 4 var monk = require('monk'); 5 var wrap = require('co-monk'); 6 var db = monk('localhost:27017/apitest'); 7 var books = wrap(db.get('books')); 8 9 app.use(route.get('/book',list)); 10 app.use(route.get('/book/:title',show)); 11 12 function *list(){ 13 var res = yield books.find({}); 14 this.body = res; 15 } 16 17 function *show(){ 18 title = decodeURI(title); 19 var res = yield books.find({title:title}); 20 this.body = res; 21 } 22 23 if(!module.parent) app.listen(3000);View Code
我们看到了generator的影子。4.在上面的express版本中我们使用了自己的数据库中的数据,那么在实际的开发过程中,可能我们会想要调试本地已有的json文件中定义的数据。于是我们同样先起来mongo:
1 mongod --dbpath ~/work/Node-KOA/koarestapi/data(我们项目目标路径)
然后把数据指向项目中的json文件:
1 mongoimport --db apitest --collection books --file data.json
注意这对json文件中的数据格式稍有要求:[ mongodb可能报错 ]
5.运行实例:
1 node --harmony app.js
然后就可以看到我们定义在data.json中的数据了 :
同样的,上面只是个简单的例子。使用koa generator-k生成的项目脚手架应该是这样的:
我们在入口文件app.js中定义基本的依赖和访问入口处理,在controller文件夹中的index.js中定义路由操作,在view中定义页面显示相关。
非常典型的MVC目录结构。
更加完整的koa版本的REST项目可以在这里看到:[ KOA-REST ]
我们实际动手写过express的项目和koa的项目的话,就会有所体会,相比于koa,express做的事情要多一些,因此他的体积也相对比较大。
在上面两个例子中我们可以看到,在express版本的例子中我们使用它内置的路由就解决了问题,但是在KOA中我们需要额外的路由中间件,其实更准确的说,koa 内核中没有捆绑任何中间件,连常用的 post body 解析都没有...但这正体现出了koa的优势,koa的体积非常小,表现力更强,它使得中间件的编写变得更加容易。其实可以说,Koa基本上就是一个只有骨架的框架,它具有极强的拓展性,我们可以自己书写可充用和更加符合实际业务场景的中间件,而不用妥协的使用Express自带的中间件。Koa虽然小,但是它通过生成器(generators JavaScript 1.7新引入的,用于解决回调嵌套的方案)减少了异步回调,提高代码的可读性和可维护性,同时改进了错误处理(Express的错误处理方式相当糟糕)。
同时,Koa是一个采用面向未来的ES6的框架,比如说随处可见的generator函数。
虽然Koa还不是那么的稳定,但是毫无疑问的它是面向未来的,下一代Nodejs框架。
那么Koa相比于Express到底优势体现在那些方面呢?总的来说,koa 的先天优势在于 generator,带来的主要好处如下:
1 更加优雅、简单、安全的中间件机制 2 更加简单、优雅地异常处理 3 更加优雅地异步编程方式
这里有更加官方的说明:[ Koa vs Express ]
其实,koa 与 express 是共享底层库的,如果你会使用 express ,那么只要理解 generator 与 koa 框架 api,就可以快速上手。
如果还没有使用过express那么不如直接开始学习Koa,从这里开始:[ koa 中文网 ]
[ install mongodb ]
[ express Routing ]
[ simple restful api ]
[ restful web app node express mongodb ]
[ koa examples ]
[ monk api ]
[ 理解RESTful架构 ]
[ RESTful api设计指南 ]
[ mongodb的一个issue ]
[ expressjs ]
[ koa 中文文档 ]
[ introduction to generator&koajs part1]
[ introduction to generator&koajs part2 ]
[ Node.js框架 express VS KOA ]
[ Koa vs Express ]
&ps-接下来文章预告:
yield语句与Generator函数
KOA实践