Koa 是下一代的 Node.js 的 Web 框架。由 Express 团队设计。目的是提供一个更小型、更富有表现力、更可靠的 Web 应用和 API 的开发基础。
随着Nodejs新版本正式支持了async和await特性,Koa也当即在2017年2月发布了V2.0.0版本,咱们称之为Koa2。
为了紧跟潮流,咱们一块儿来经过一个实际的小项目来学习Koa2。html
既然是为了完整的学习Koa2,确定不能只作一个“Hello world!”,咱们能够作一个“Hello Koa2!”。呵呵,言归正传。什么项目既足够小,又能完整的学习一个web框架了? 固然是框架最流行的"Hello world"项目:TODO应用。node
本次计划开发的TODO List应用使用先后端分离的设计,采用REST(Representational State Transfer)架构。REST是Roy Thomas Fielding在2000年的论文Architectural Styles and
the Design of Network-based Software Architectures中提出的。git
既然要采用REST架构,那么对REST咱们就须要有一个较全面的了解。github
RESTful API与用户通信的协议,一采用HTTPS协议。(练手项目为了简单,就先采用HTTP协议)web
有两种指明API版本的方法:express
A. 版本号放到HTTPS请求的头信息的Accept字段中:json
Accept: vnd.example-com.foo+json; version=1.0 Accept: vnd.example-com.foo+json; version=1.1 Accept: vnd.example-com.foo+json; version=2.0 #github采用以下的形式指明版本号 Accept: application/vnd.github.v3+json
B 将版本号放到URL中后端
https://api.example.com/v1/ #豆瓣API https://api.douban.com/v2/book/isbn/:name
尽可能将API部署在专用域名下。例如github和豆瓣的API就是部署在专用域名下。此种方式适用于应用比较复杂和庞大,在规模化时灵活性比较好。api
https://api.douban.com/v2/book/isbn/:name https://api.github.com/ https://api.example.com
在简单的状况下,也能够将API部署到主域名之下。这样能够采用相同的框架同时支持站点和API。数组
https://example.org/api/
同时API的根返回API的相关说明是一个较好的实践。github的根API就是一个典型的例子。
一个端点就是指向特定资源或资源集合的URL。以构建一个虚拟的动物园的API为例,咱们有多个动物园,每一个动物园包含有多种的动物,员工,那么端点能够设计以下:
https://api.example.org/v1/zoos https://api.example.org/v1/animals https://api.example.org/v1/employees
对具体资源的操做类型,由HTTP动词表示。
经常使用的HTTP动词有以下五个:
不经常使用的还有以下的两个:
仍是以动物园的API为例。对于每个端点,能够列出全部可行的HTTP动词和端点的组合。
GET /zoos: 列出全部动物 POST /zoos: 新建一个动物园 GET /zoos/ZID: 获取指定动物园的信息 PUT /zoos/ZID: 更新指定的动物园(提供该动物园的完整信息) PATCH /zoos/ZID: 更新指定的动物园(提供该动物园的部分信息) DELETE /zoos/ZID: 删除指定的动物园 GET /zoos/ZID/animals: 获取指定动物园的全部动物 DELETE /zoos/ZID/animals/AID: 删除指定动物园的指定动物 GET /zoos/ZID/employees: 列出指定动物园的全部雇员 POST /zoos/ZID/employees: 在指定动物园雇佣一个新雇员 DELETE /zoos/ZID/employees/EID: 从指定动物园解雇一个指定的雇员
若是记录的数据量比较多,API就应该提供参数,对返回的结果进行过滤。经常使用的参数有以下一些:
#limit和offset就能实现分页 ?limit=10:指定返回记录的数量 ?offset=10:指定返回记录的开始位置。 ?page=2&per_page=100:指定第几页,以及每页的记录数。 #为了将总数发给客户端,使用订制的HTTP头: X-Total-Count. #连接到下一页或上一页能够在HTTP头的link规定,遵循Link规定: Link: <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=15&limit=5>; rel="next", <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=50&limit=3>; rel="last", <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=0&limit=5>; rel="first", <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=5&limit=5>; rel="prev",
对返回的结果按照某个属性排序以及排序顺序。
?sortby=name&order=asc:指定返回结果按照哪一个属性排序,以及排序顺序。 #根据生产者降序和模型升序排列 ?sort=-manufactorer,+model
移动端可以显示其中一些字段,它们其实不须要一个资源的全部字段,给API消费者一个选择字段的能力,这会下降网络流量,提升API可用性。
#仅须要制造商,类型,id和颜色字段 ?fields=manufacturer,model,id,color
服务器向用户返回的状态码和提示信息,HTTP 1.1中常见的有如下一些(方括号中是该状态码对应的HTTP动词)。
200 OK - [GET]:服务器成功返回用户请求的数据,该操做是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:客户端要求服务器删除一个资源,服务器删除成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操做,该操做是幂等的。 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [*] 表示用户获得受权(与401错误相对),可是访问是被禁止的。 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操做,该操做是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(好比用户请求JSON格式,可是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再获得的。 422 Unprocesable entity - [POST/PUT/PATCH] 当建立一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将没法判断发出的请求是否成功。
状态码范围(Status Code Ranges)
1xx 保留给底层HTTP功能使用 2xx 保留给成功消息使用 3xx 保留给重定向使用,通常API不会使用此类状态 4xx 保留给客户端错误使用。例如,客户端提供了一些错误的数据或请求了不存在的内容。这些请求应该是幂等的,不会改变任何服务器的状态。 5xx 保留给服务器端错误用的。这些错误经常是从底层的函数抛出来的,而且开发人员也一般无法处理。发送这类状态码的目的是确保客户端能获得一些响应。收到5xx响应后,客户端没办法知道服务器端的状态,因此这类状态码是要尽量的避免。
完整状态码列表能够参考RFC2616。
当使用不一样的HTTP动词向服务器请求时,客户端须要在返回结果里面拿到一系列的信息。下面的列表是很是经典的RESTful API定义:
GET /collection: 返回资源对象列表(数组) GET /collection/resource: 返回单个的资源对象 POST /collection: 返回新建立的资源对象 PUT /collection/resource: 返回完整的资源对象 PATCH /collection/resource: 返回完整的资源对象 DELETE /collection/resource: 返回一个空文档
当一个客户端建立一个资源时,她们经常不知道新建资源的ID(也许还有其余的属性,如建立和修改的时间戳等)。这些属性将在随后的请求中返回,而且做为刚才POST请求的一个响应结果。
RESTful API最好作到Hypermedia,即返回结果中提供连接,连向其余API方法,使得用户不查文档,也知道下一步应该作什么。
好比,当用户向api.example.com的根目录发出请求,会获得这样一个文档。
{ "link": { "rel": "collection https://www.example.com/zoos", "href": "https://api.example.com/zoos", "title": "List of zoos", "type": "application/vnd.yourformat+json" } }
上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么API了。rel表示这个API与当前网址的关系(collection关系,并给出该collection的网址),href表示API的路径,title表示API的标题,type表示返回类型。
Hypermedia API的设计被称为HATEOAS。Github的API就是这种设计,访问api.github.com会获得一个全部可用API的网址列表。
{ "current_user_url": "https://api.github.com/user", "authorizations_url": "https://api.github.com/authorizations", // ... }
从上面能够看到,若是想获取当前用户的信息,应该去访问api.github.com/user,而后就获得了下面结果。
{ "message": "Requires authentication", "documentation_url": "https://developer.github.com/v3" }
上面代码表示,服务器给出了提示信息,以及文档的网址。
项目已经发布到github: koa-todo
参考文章:
阮一峰 RESTful API 设计指南
做者:Q_幽兰_Q 连接:https://www.jianshu.com/p/c37a13506753 來源:简书 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。