Koa2实战练手(一)------ 学习RESTful API

风格不统一 提交于 2020-04-07 10:30:08

Koa 是下一代的 Node.js 的 Web 框架。由 Express 团队设计。目的是提供一个更小型、更富有表现力、更可靠的 Web 应用和 API 的开发基础。
随着Nodejs新版本正式支持了async和await特性,Koa也立即在2017年2月发布了V2.0.0版本,我们称之为Koa2。
为了紧跟潮流,我们一起来通过一个实际的小项目来学习Koa2。

一、项目设计

既然是为了完整的学习Koa2,肯定不能只做一个“Hello world!”,我们可以做一个“Hello Koa2!”。呵呵,言归正传。什么项目既足够小,又能完整的学习一个web框架了? 当然是框架最流行的"Hello world"项目:TODO应用。

本次计划开发的TODO List应用使用前后端分离的设计,采用REST(Representational State Transfer)架构。REST是Roy Thomas Fielding在2000年的论文Architectural Styles and
the Design of Network-based Software Architectures
中提出的。

二、学习REST

既然要采用REST架构,那么对REST我们就需要有一个较全面的了解。

2.1 REST设计原则

  1. 每个URI表示一种资源(resource)
  2. URI应该使用名称而不是动词
  3. 使用复数名词
  4. GET方法不能改变状态
  5. HTTP协议中四种方法对应四种基本的操作:
    • GET: 获取资源(select)
    • POST:新建资源(create)
    • PUT:更新资源(update)
    • DELETE:删除资源(delete)
  6. 其他方法
    • HEAD:获取资源的元数据(meta data),例如数据的hash值或则资源的最后更新时间
    • OPTIONS:返回当前资源允许客户做哪些操作;
  7. 使用子资源表示关系
  8.  

2.2、协议

RESTful API与用户通讯的协议,一采用HTTPS协议。(练手项目为了简单,就先采用HTTP协议)

2.3、版本(Versioning)

有两种指明API版本的方法:

A. 版本号放到HTTPS请求的头信息的Accept字段中:

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

2.4、API根地址

尽量将API部署在专用域名下。例如github和豆瓣的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就是一个典型的例子。

2.5 端点(Root Endpoint)

一个端点就是指向特定资源或资源集合的URL。以构建一个虚拟的动物园的API为例,我们有多个动物园,每个动物园包含有多种的动物,员工,那么端点可以设计如下:

https://api.example.org/v1/zoos
https://api.example.org/v1/animals
https://api.example.org/v1/employees

2.6 HTTP动词

对具体资源的操作类型,由HTTP动词表示。

常用的HTTP动词有如下五个:

  • GET(SELECT): 获取资源
  • POST(CREATE):新建资源
  • PUT(UPDATE):更新资源(客户端提供改变后的完整资源)
  • PATCH(UPDATE):在服务器更新资源(客户端只提供改变的属性)
  • DELETE(DELETE):删除资源

不常用的还有如下的两个:

  • HEAD:获取资源的元数据(meta data),例如数据的hash值或则资源的最后更新时间
  • OPTIONS:返回当前资源允许客户做哪些操作;

还是以动物园的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: 从指定动物园解雇一个指定的雇员

2.7 过滤信息和分页(Filtering & Paging)

如果记录的数据量比较多,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",

2.8 排序(Sorting)

对返回的结果按照某个属性排序以及排序顺序。

?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。

#根据生产者降序和模型升序排列
?sort=-manufactorer,+model

2.9 字段选择(Field selection)

移动端能够显示其中一些字段,它们其实不需要一个资源的所有字段,给API消费者一个选择字段的能力,这会降低网络流量,提高API可用性。

#仅需要制造商,类型,id和颜色字段
?fields=manufacturer,model,id,color 

2.10 状态码(Status Codes)

服务器向用户返回的状态码和提示信息,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

2.11 返回结果

当使用不同的HTTP动词向服务器请求时,客户端需要在返回结果里面拿到一系列的信息。下面的列表是非常经典的RESTful API定义:

GET /collection: 返回资源对象列表(数组)
GET /collection/resource: 返回单个的资源对象
POST /collection: 返回新创建的资源对象
PUT /collection/resource: 返回完整的资源对象
PATCH /collection/resource: 返回完整的资源对象
DELETE /collection/resource: 返回一个空文档

当一个客户端创建一个资源时,她们常常不知道新建资源的ID(也许还有其他的属性,如创建和修改的时间戳等)。这些属性将在随后的请求中返回,并且作为刚才POST请求的一个响应结果。

2.12 Hypermedia API

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
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!