Jonathan1314

导航

Python自动化开发 - RESTful API

本节内容

1.  RESTful 简介

2.  RESTful 设计指南

3.  Django REST Framework 最佳实践

4.  理论拓展与开放平台

5.  API文档化与测试

 

一  RESTful 简介

 

 

传统理解,软件和网络是两个不同的领域,很少有交集:软件开发主要针对单机环境,网络则主要研究系统之间的通信

互联网的兴起,使得两个领域开始融合,现在我们必须考虑,如何开发在互联网环境中使用的软件

网站即软件,这种“互联网软件”采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时、高并发等特点

RESTful架构,就是目前最流行的一种互联网软件架构

1. 起源

REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的

Fielding 一个非常重要的人物,HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一、Apache基金会的第一认主席

2. 名称

REST,Representational State Transfer,即“表现层状态转化”,如果一个架构符合REST原则,就称为RESTful架构

3. 资源(Resources)

REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"

所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是

一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,

因此URI就成了每一个资源的地址或独一无二的识别符。

所谓"上网",就是与互联网上一系列的"资源"互动,调用它的URI

4. 表现层(Representaion)

"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。

比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,

也可以用PNG格式表现。

URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于

"表现层"范畴,而URI应该只代表"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,

这两个字段才是对"表现层"的描述。

5. 状态转化(State Transfer)

访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,

必须通过某种手段,让服务器端发生“状态转化”(State Transfer),而这种转化是建立在表现层之上的,所以就是“表现层状态转化”

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。

它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源

6. 综述

综合上面的解释,我们总结一下什么是RESTful架构:

  (1)每一个URI代表一种资源;

  (2)客户端和服务器之间,传递这种资源的某种表现层;

  (3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

7. 设计误区

最常见的一种设计错误,就是URI包含动词。因为"资源"表示一种实体,所以应该是名词,URI不应该有动词,动词应该放在HTTP协议中

举例来说,某个URI是/posts/show/1,其中show是动词,这个URI就设计错了,正确的写法应该是/posts/1,然后用GET方法表示show

如果某些动作是HTTP动词表示不了的,你就应该把动作做成一种资源。比如网上汇款,从账户1向账户2汇款500元,错误的URI是:

POST /accounts/1/transfer/500/to/2

正确的写法是把动词transfer改成名词transaction,资源不能是动词,但是可以是一种服务:

POST /transaction HTTP/1.1
Host: 127.0.0.1
 
from=1&to=2&amount=500.00

 

二  RESTful API 设计指南

 

 

接下来介绍RESTful API 的设计细节,探讨如何设计一套合理、好用的API

1. 协议

API与用户的通信协议, 总是 使用https协议

2. 域名

应该尽量将API部署在专用域名之下

https://api.example.com

如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下

https://example.org/api/

3. 版本(Versioning)

可以将API的版本号放入URL

https://api.example.com/v1/

另一种做法是,将版本号放在HTTP头信息中,但不如放入URL方便和直观。Github采用这种做法

4. 路径(Endpoint)

路径又称“终点”(endpoint),表示API的具体网址

在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应

一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。

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

5. HTTP动词

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

常用的HTTP动词有下面五个(括号里是对应的SQL命令)

GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
DELETE(DELETE):从服务器删除资源。

还有两个不常用的HTTP动词

HEAD:获取资源的元数据。
OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

下面是一些例子

GET /zoos:列出所有动物园
POST /zoos:新建一个动物园
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

6. 过滤信息(Filtering)

如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果

下面是一些常见的参数

?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。

比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的

7. 状态码(Status Codes)

服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的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 - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。  

状态码的完全列表参见这里

8. 错误处理(Error Handling)

 如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可

{
    error: "Invalid API key"
} 

9. 返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范

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

10.  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"
}

上面代码表示,服务器给出了提示信息,以及文档的网址

11.其他

API的身份认证应该使用OAuth 2.0框架 

服务器返回的数据格式,应该尽量使用JSON,避免使用XML。

 

三  Django REST Framework 最佳实践

 

 

注意:这是版本v.3+的REST framework文档

Django REST framework 是一个强大且灵活的工具包,用以构建Web APIs。 
为什么要使用REST framework? 
在线可视的API,对于赢得你的开发者们十分有用 

验证策略涵盖了OAuth1aOAuth2 

- 同时支持ORM非ORM数据源的序列化 

- 可以配置各个环节,若无需更多强大特性,使用一般基于方法(function-based)的视图(views)即可

大量的文档,强力的社区支持 

- 大公司如同MozillaEventbrite,也是忠实的使用者

 1.  配置要求

REST framework 有以下的要求:

  • Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
  • Django (1.7+, 1.8, 1.9, 1.11)

下面是可选的包:

  • Markdown (2.1.0+) - Markdown为可视化 API 提供了支持.
  • django-filter (0.9.2+) - 过滤支持.
  • django-crispy-forms - 为过滤,提供了改良的HTML呈现.
  • django-guardian (1.1.1+) - 对象层面的权限支持.

 2.  安装部署

使用pip安装框架及所有的你需要的可选依赖包

pip  install  -i  https://pypi.doubanio.com/simple/  --trusted-host pypi.doubanio.com djangorestframework
pip  install  -i  https://pypi.doubanio.com/simple/  --trusted-host pypi.doubanio.com markdown
pip  install  -i  https://pypi.doubanio.com/simple/  --trusted-host pypi.doubanio.com django-filter

…又或者从github上clone该项目

git clone git@github.com:tomchristie/django-rest-framework.git

将 'rest_framework' 添加到你的 'INSTALLED_APPS' 设置里

INSTALLED_APPS = (
    ...
    'rest_framework',
)

如果你需要使用可视化的API,你也许就需要添加REST Framework的登陆/登出视图。在项目的 urls.py文件里,添加下面的内容:

urlpatterns = [
    ...
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
] 

3.  示例

让我们看一个简单用例:如何用REST framework 来搭建一个简单的支持modle的API 

我们将创建一个读/写API,来处理我们项目中的用户信息。 
任何REST framework的全局设置,都存放在一个配置字典(dictionary,有些语言如Java中的map)中,名为REST_FRAMEWORK

我们从以下的操作开始,把下面的内容添加到项目的settings.py模块中:

REST_FRAMEWORK = {
    # 使用Django的标准`django.contrib.auth`权限管理类,
    # 或者为尚未认证的用户,赋予只读权限.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
    ]
}

这是项目目录下urls.py模块:

from django.conf.urls import url, include
from django.contrib.auth.models import User
from rest_framework import routers, serializers, viewsets

# Serializers定义了API的表现.
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'is_staff')

# ViewSets 定义了 视图(view) 的行为.
class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

# Routers 提供了一种简单途径,自动地配置了URL。
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)

# 使用自动的URL路由,让我们的API跑起来。
# 此外,我们也包括了登入可视化API的URLs。
urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

启动项目 python manage runserver 8000 浏览器 http://127.0.0.1:8000/里,打开新建的’users’ API了

使用右上角的登陆控制,可以对系统用户进行新增和删除操作

 

四 理论拓展与开放平台

 

 

1.  通俗语言解释REST和RESTful API

URL定位资源,用HTTP动词(GET,POST,PUT,DELETE)描述操作

  • REST描述的是网络中clien和server的一种交互形式;REST本身不实用,实用的是如何设计RESTful API(REST风格的网络接口)

  • Server提供的RESTful API中,URL只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心

  • 用HTTP协议里的动词来实现资源的获取,添加,修改和删除等操作

  • Server和Client之间传递某种资源的一个表现形式。如json、xml传输文本,png、jpg传输图片等

  • 用HTTP Status Code 传递Server的状态信息

“古代”网页是前端和后端融在一起,比如PHP,JSP等。在之前的桌面时代问题不大,但移动互联网的发展,各种类型的Client层出不穷,

RESTful可以通过统一的接口为Web,IOS和Android提供服务。由此可见,Web,iOS,Android和第三方开发者变为平等的角色

通过一套API来共同消费Server提供的服务,前端和后端实现开发分离。

附挺有意思的解释:

传统的接口设计,就是过程式的,每个特定的动作有特定的接口。

RESTful,其实就是一个面向对象的接口,接口是对象,这个对象有GET,POST,PUT,DELETE等等成员函数(接口)

 

2. 常见的第三方API开放平台

https://developer.github.com/v3/

api.jd.com

http://open.weibo.com/wiki/%E5%BE%AE%E5%8D%9AAPI

 

五 API文档化与测试

 

 

API开发完毕各种文档及时整理,包括与产品、前端以及与向部门开放接口说明

1.  接口文档

接口描述

  简单描述接口的逻辑和作用

接口地址

  正式和测试

请求方法

  GET、POST、PUT、DELETE

请求参数

  参数名称  类型 描述  是否必填 排序 分页 搜索  关联表处理 批量操作

响应内容

  返回的字段名  格式json

错误代码

  尽量与HTTP保持一致

实例

  各种情况的演示实例

开发相关

需求详细描述、需求流程图、涉及库表

2. 测试

测试工具推荐 POSTMAN

 

参考与拓展

 

 

1. 阮一峰 RESTful API 设计指南

http://www.ruanyifeng.com/blog/2014/05/restful_api.html

2. GitHub 版本示例  

https://developer.github.com/v3/media/#request-specific-version

3. HTTP状态码汇总

http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

4. HATEOAS简介

https://www.ibm.com/developerworks/cn/java/j-lo-SpringHATEOAS/

5. rest_framework 参考指南

http://www.django-rest-framework.org/

http://blog.csdn.net/ppppfly/article/details/51077433

6. 怎样用通俗的语言解释REST以及RESTful

https://www.zhihu.com/question/28557115

posted on 2017-07-14 14:45  Jonathan1314  阅读(7940)  评论(0编辑  收藏  举报