2019独角兽企业重金招聘Python工程师标准>>>
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设计原则
- 每个URI表示一种资源(resource)
- URI应该使用名称而不是动词
- 使用复数名词
- GET方法不能改变状态
- HTTP协议中四种方法对应四种基本的操作:
- GET: 获取资源(select)
- POST:新建资源(create)
- PUT:更新资源(update)
- DELETE:删除资源(delete)
- 其他方法
- HEAD:获取资源的元数据(meta data),例如数据的hash值或则资源的最后更新时间
- OPTIONS:返回当前资源允许客户做哪些操作;
- 使用子资源表示关系
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: ; rel="next",
; rel="last",
; rel="first",
; 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
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。