RESTful API


什么是REST

一种软件架构风格、设计风格、而不是标准,只是提供了一组设计原则和约束条件。它主要用户客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。

REST全称是Representational State Transfer,表征性状态转移。首次在2000年Roy Thomas Fielding的博士论文中出现,Fielding是一个非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者,Apache服务器软件的作者之一,Apache基金会的第一任主席。所以,他的这篇论文一经发表,就引起了广泛的关注。

论文:

本文研究计算机科学两大前沿----软件和网络----的交叉点。长期以来,软件研究主要关注软件设计的分类、设计方法的演化,很少客观地评估不同的设计选择对系统行为的影响。而相反地,网络研究主要关注系统之间通信行为的细节、如何改进特定通信机制的表现,常常忽视了一个事实,那就是改变应用程序的互动风格比改变互动协议,对整体表现有更大的影响。我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。

REST爆发

其实在REST架构推出的十几年间,它并没有一路高歌的发展,真正的大范围推广是在2013年之后,伴随着移动端的飞速发展,越来越多人的开始意识到,网站即软件,而且是一种新型的软件。

这种"互联网软件采用"客户端/服务器"模式,也就是我们常说的C/S模式,这一切建立在分布式体系上,通过互联网通信,具有高延时,高并发等特点。

网站开发,完全采用软件开发开发的模式。但传统上,软件和网络是两个不同的领域,很少有交集,软件开发主要针对单机环境,网络则主要研究系统之间的通信。我们需要考虑的是如何开发在互联网环境中使用软件。

理解RESTful

要理解RESTful架构,最好的就是去理解它的单词 Representational State Transfer 到底是什么意思,它的每一个词到底要表达什么。

REST的释义,"表现层状态转化",其实这省略了主语。“表现层”其实指的是“资源(Resource)”的“表现层”。

资源(Resource)

所谓“资源”,就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本,一张图片,一首歌曲,一种服务,总之就是一个具体的实例。你可以使用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以了,因此URI就成了每一个资源的地址或独一无二的识别符。所谓“上网”就是与互联网上一系列的“资源”互动,调用它们的URI。

表现层(Representation)

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

URI只代表资源的实体,不代表它的形式。严格地说,有些网站最后的”.html“后缀名是不必要的,因为这个后缀表示格式,属于”表现层“范畴,而URI应该只代表”资源“的位置。它的具体表现形式,应该在HTTP请求头的信息中使用Accept和Content-Type字段指定。

状态转换(State Transfer)

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

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务端。因此,如果客户端想要操作服务器,就必须通过某种手段,让服务器端发生”状态转换(State Transfer)“。而这种转换是建立在表现层之上的,所以就是”表现层状态转化“。

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议中,四个表示操作方式的动词:GET,POST,PUT,DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可用于更新资源),PUT用来更新资源,DELETE用来删除资源

到底什么是RESTful架构

  1. 每一个URI代表一种资源

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

  3. 客户端通过四个HTTP动词,对服务端资源进行操作,实现”表现层状态转换“

RESTful API设计

协议

API与用户的通信协议,通常使用HTTP(S)协议。

域名

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

http://api.hello.com
 

如果确定API很简单,不会有大规模扩充,可以考虑放在主域名之下。

http://www.hello.com/api/
 
版本

应该将API的版本号放入URL。

http://api.rock.com/v1/
 

也有做法是将版本号放在HTTP的头信息中,但不如放在URL中方便和直观。GITHUB是这么搞的。

路径(Endpoint)

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

在RESTful架构中,每个网址代表一种资源(Resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的”集合“(collection),所以API中的名词也应该使用复数。

HTTP动词

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

HTTP常用动词

  • GET(SELECT):从服务器取出资源

  • POST(CREATE or UPDATE):在服务器创建资源或更新资源

  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)

  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)

  • DELETE(DELETE):从服务器删除资源

  • HEAD:获取资源的元数据

  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的、

示例

  • GET /students:获取所有学生

  • POST /students:新建学生

  • GET /students/id:获取某一个学生

  • PUT /students/id :更新某个学生的信息(需要提供学生的全部信息)

  • PATCH /students/id:更新某个学生的信息(需要提供学生变更部分信息)

  • DELETE /students/id:删除某个学生

过滤信息(Filtering)

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

  • ?limit=10

  • ?offset=10

  • ?page=2&per_page=20

  • ?sortby=name&order=desc

  • ?student_id=id

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复,比如 GET /students/id 和 ?student_id=id

状态码

服务器向用户返回的状态码和提示信息,常见的有以下一些地方

  • 200 OK - [GET]:服务器成功返回用户请求的数据

  • 201 CREATED -[POST/PUT/PATCH]:用户新建或修改数据成功

  • 202 Accepted - [*] :表示一个请求已经进入后台排队(异步任务)

  • 204 NO CONTENT - [DELETE]:表示数据删除成功

  • 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误

  • 401 Unauthorized - [*] :表示用户没有权限(令牌,用户名,密码错误)

  • 403 Forbidden - [*]:表示用户得到授权,但是访问是被禁止的

  • 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录

  • 406 Not Acceptable - [*]:用户请求格式不可得

  • 410 Gone - [GET] :用户请求的资源被永久移除,且不会再得到的

  • 422 Unprocesable entity -[POST/PUT/PATCH]:当创建一个对象时,发生一个验证错误

  • 500 INTERNAL SERVER EROR - [*] :服务器内部发生错误

错误处理

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

返回结果

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

  • GET /collection:返回资源对象的列表(数组,集合)

  • GET /collection/id:返回单个资源对象

  • POST /collection:返回新生成的资源对象

  • PUT /collection/id:返回完整的资源对象

  • PATCH /collection/id:返回完整的资源对象

  • DELETE /collection/id:返回一个空文档

使用链接关联资源

RESTful API可以做到超媒体,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。

{
    "link": {
        "rel":   "collection https://www.hello.com/zoostudents",
        "href":  "https://api.hello.com/students",
        "title": "List of students",
        "type":  "application/vnd.yourformat+json"
      }
}
 
  • rel:表示这个API与当前网址的关系

  • href:表示API的路径

  • title:表示API的标题

  • type:表示返回的类型

其它
  • 服务器返回的数据格式,应该尽量使用JSON

  • API的身份认证应该使用OAuth2.0框架

Flask-RESTful

https://flask-restful.readthedocs.io/en/latest/

基本使用

  • 安装

# pip 安装
pip install flask-restful
# 源码安装
git clone https://github.com/flask-restful/flask-restful.git
python setup.py develop
 
  • 创建Resource实现类

class HelloRESTful(Resource):
    def get(self):
        return {"data":"Hello GET"}
    def post(self):
        return {'data':'hello POST'}
 
  • 创建API对象,并注册路由

# ① 创建并初始化
api = API(app)
# ② 创建,之后初始化
api = API()
api.init_app(app)
# 注册路由 
api.add_resource(HelloRESTFul,"/")

字段格式化

fields进行定义
marshal_with进行使用
    特性
        显示我们设计的数据结构
        默认返回的数据如果在预定义结构中不存在,数据会被自动过滤
        如果返回的数据在预定义的结构中存在,数据会正常返回
        如果返回的数据比预定义结构中的字段少,预定义的字段会呈现一个默认值
        
    定义字段输出
        使用字典进行定义
        常用都是基本类型: String, Integer
        
            # 格式化字段
            user_fields = {
                'msg': fields.String,
                'status': fields.Integer,
                'data': fields.String(attribute='private_data'),
                'default_data': fields.String(default='1')
            }
        定义好的格式通过装饰器进行使用
            @marshal_with(需要返回的数据格式),  return返回字典就ok了
                class Users(Resource):
                    @marshal_with(user_fields)
                    def get(self):
                        return {'msg':'呵呵', 'data':'没有数据', 'age':'22', 'private_data':'表中数据'}
    级联数据: 嵌套字典
        Nested
        
            # 格式化字段
            usermodel_fileds = {
                'id': fields.Integer,
                'name': fields.String,
            }
            user2_fields = {
                'msg': fields.String(default='ok'),
                'status': fields.Integer(default=1),
                'data': fields.Nested(usermodel_fileds)
            }
        
    结构允许嵌套列表
        fields.List(fields.Nested) 
        
            # 格式化字段
            usermodel_fileds = {
                'id': fields.Integer,
                'name': fields.String,
            }
            users3_fields = {
                'status': fields.String(default=1),
                'msg': fields.String,
                'data': fields.List(fields.Nested(usermodel_fileds))
            }
 

URL

连接字段
    就是将当前数据的操作api暴露出来
    根据提供的url和唯一标识进行数据操作
# 格式化字段
usermodel_fileds = {
    'id': fields.Integer,
    'name': fields.String,
    'url': fields.Url('id', absolute=True)
}
# 在add_resource中提供对应的endpoint
api.add_resource(Users4, '/user4/', endpoint='id')
 

参数解析

可以不通过request.form或request.args获取参数, 而是通过reqparse.RequestParser来解析
    # 参数转换器
    parser = reqparse.RequestParser()
    parser.add_argument('name', type=str, action='append')  # 支持多个name
    parser.add_argument('id', type=int, required=True, help='id是必须的') # 必需参数
    parser.add_argument('fldt_active', type=str, location='cookies')  # 获取cookies中的数据
    class Users4(Resource):
        def get(self):
            parse = parser.parse_args()
            user_name = parse.get('name')
            id = parse.get('id')
            fldt_active = parse.get('fldt_active')
            return {'name': user_name, 'id': id, 'fldt_active':fldt_active}
    
 

Flask (五) RESTful API的更多相关文章

  1. flask开发restful api系列(8)-再谈项目结构

    上一章,我们讲到,怎么用蓝图建造一个好的项目,今天我们继续深入.上一章中,我们所有的接口都写在view.py中,如果几十个,还稍微好管理一点,假如上百个,上千个,怎么找?所有接口堆在一起就显得杂乱无章 ...

  2. flask开发restful api

    flask开发restful api 如果有几个原因可以让你爱上flask这个极其灵活的库,我想蓝图绝对应该算上一个,部署蓝图以后,你会发现整个程序结构非常清晰,模块之间相互不影响.蓝图对restfu ...

  3. Flask之RESTFul API前后端分离

    Flask之RESTFul API前后端分离 一:虚拟环境搭建的两种方式 1 pipenv的使用 pip install --user pipenv安装pipenv在用户目录下 py -m site ...

  4. flask开发restful api系列(7)-蓝图与项目结构

    如果有几个原因可以让你爱上flask这个极其灵活的库,我想蓝图绝对应该算上一个,部署蓝图以后,你会发现整个程序结构非常清晰,模块之间相互不影响.蓝图对restful api的最明显效果就是版本控制:而 ...

  5. flask开发restful api系列(6)-配置文件

    任何一个好的程序,配置文件必不可少,而且非常重要.配置文件里存储了连接数据库,redis的用户密码,不允许有任何闪失.要有灵活性,用户可以自己配置:生产环境和开发环境要分开,最好能简单的修改一个东西, ...

  6. flask开发restful api系列(1)

    在此之前,向大家说明的是,我们整个框架用的是flask + sqlalchemy + redis.如果没有开发过web,还是先去学习一下,这边只是介绍如果从开发web转换到开发移动端.如果flask还 ...

  7. 使用 Flask 实现 RESTful API

    原文出处: Luis Rei   译文出处:nummy 简介 首先,安装Flask     1 pip install flask 假设那你已经了解RESTful API的相关概念,如果不清楚,可以阅 ...

  8. Python使用Flask实现RESTful API,使用Postman工具、requests库测试接口

    RESTful是一种API设计规范.在RESTful架构中,主要使用POST,DELETE,PUT和GET四种HTTP请求方式分别对指定的URL资源进行增删改查操作. RESTful之前的做法: /u ...

  9. 使用 Python 和 Flask 设计 RESTful API

    近些年来 REST (REpresentational State Transfer) 已经变成了 web services 和 web APIs 的标配. 在本文中我将向你展示如何简单地使用 Pyt ...

随机推荐

  1. Android P2P语音通话实现

    1.http://www.cnblogs.com/milospooner/archive/2012/07/13/2590950.html 2.http://my.oschina.net/sanshan ...

  2. Android and iOS 判断是那个系统访问。

    <!-- 如果是安卓就加载. --> <neq name="Think.server.HTTP_USER_AGENT|strstr='Android'" valu ...

  3. 696. Count Binary Substrings统计配对的01个数

    [抄题]: Give a string s, count the number of non-empty (contiguous) substrings that have the same numb ...

  4. opennebula 一些问t题讨论

    ou_ian - June 8th, 2011 11:13 am非常想请教一下如何设置VM的ip为DHCP? 我们的VM都需要通过eth0 (通过公司的DHCP获得ip)来连接到公司的网络(Inter ...

  5. Docker学习笔记_Dockerfile常用指令

    Dockerfile常用指令

  6. 基于Ubuntu16搭建Hadoop大数据完全分布式环境

    [目的]:学习大数据 在此记录搭建大数据的过程. [系统环境] 宿主机操作系统:Win7 64位 虚拟机软件:Vmware workstation 12 虚拟机:Ubuntu 16 64位桌面版 [步 ...

  7. 下载Redis

    1.下载当前Redis 官网:https://redis.io/ 当前稳定版本是4.0.11,如下图,点Download it下面的链接进行下载 2.下载历史版本的Resis 网址: http://d ...

  8. =面试题:java面试基本方向 背1 有用 项目二技术学完再看

    一.Java基础 1. 集合框架A)集合中泛型优点? 将运行期的ClaasCastException 转到编译期异常.  泛型还提供通配符 1)HashMap---允许一个键为null,允许多个值为n ...

  9. 面试题:Java集合面试题(40道) 背1

    Java集合框架为Java编程语言的基础,也是Java面试中很重要的一个知识点.这里,我列出了一些关于Java集合的重要问题和答案. 1.Java集合框架是什么?说出一些集合框架的优点? 每种编程语言 ...

  10. VMWare、Ubuntu Server 18.04 共享文件夹

    背景:VMWare选项中配置了共享文件夹,装完Ubuntu Server 18.04在 /mnt/下都没有 hgfs文件夹,更别提共享文件夹了 参考:Ubuntu16.04版安装VMwareTools ...