首页
学习
活动
专区
工具
TVP
发布

基于 Flask 提供 RESTful Web 服务

关键时刻,第一时间送达!

什么是 REST

REST 全称是 Representational State Transfer,翻译成中文是『表现层状态转移』,估计读者看到这个词也是云里雾里的,我当初也是!这里,我们先不纠结这个词到底是什么意思。事实上,REST 是一种 Web 架构风格,它有六条准则,满足下面六条准则的 Web 架构可以说是 Restuful 的。

客户端-服务器(Client-Server)服务器和客户端之间有明确的界限。一方面,服务器端不再关注用户界面和用户状态。另一方面,客户端不再关注数据的存储问题。这样,服务器端跟客户端可以独立开发,只要它们共同遵守约定。

无状态(Stateless)来自客户端的每个请求必须包含服务器所需要的所有信息,也就是说,服务器端不存储来自客户端的某个请求的信息,这些信息应由客户端负责维护。

可缓存(Cachable)服务器的返回内容可以在通信链的某处被缓存,以减少交互次数,提高网络效率。

分层系统(Layered System)允许在服务器和客户端之间通过引入中间层(比如代理,网关等)代替服务器对客户端的请求进行回应,而且这些对客户端来说不需要特别支持。

统一接口(Uniform Interface)客户端和服务器之间通过统一的接口(比如 GET, POST, PUT, DELETE 等)相互通信。

支持按需代码(Code-On-Demand,可选)服务器可以提供一些代码(比如 Javascript)并在客户端中执行,以扩展客户端的某些功能。

使用 Flask 提供 REST Web 服务

REST Web 服务的核心概念是资源(resources)。资源被 URI(Uniform Resource Identifier, 统一资源标识符)定位,客户端使用 HTTP 协议操作这些资源,我们用一句不是很全面的话来概括就是:URI 定位资源,用 HTTP 动词(GET, POST, PUT, DELETE 等)描述操作。下面列出了 REST 架构 API 中常用的请求方法及其含义:

设计一个简单的 Web Service

现在假设我们要为一个 blog 应用设计一个 Web Service。

首先,我们先明确访问该 Service 的根地址是什么。这里,我们可以这样定义:

http://[hostname]/blog/api/

然后,我们明确有哪些资源是要公开的。可以知道,我们这个 blog 应用的资源就是 articles。

下一步,我们要明确怎么去操作这些资源,如下所示:

为了简便,我们定义一篇 article 的属性如下:

id:文章的 id,Numeric 类型

title: 文章的标题,String 类型

content: 文章的内容,TEXT 类型

至此,我们基本完成了这个 Web Service 的设计,下面我们就来实现它。

使用 Flask 提供 RESTful api

在实现这个 Web 服务之前,我们还有一个问题没有考虑到:我们应该怎么存储我们的数据。毫无疑问,我们应该使用数据库,比如 MySql、MongoDB 等。但是,数据库的存储不是我们这里要讨论的重点,所以我们采用一种偷懒的做法:使用一个内存中的数据结构来代替数据库。

GET 方法

下面我们使用 GET 方法获取资源。

# -*- coding: utf-8 -*-

fromflaskimportFlask,jsonify,abort,make_response

app=Flask(__name__)

articles=[

{

'id':1,

'title':'the way to python',

'content':'tuple, list, dict'

},

{

'id':2,

'title':'the way to REST',

'content':'GET, POST, PUT'

}

]

@app.route('/blog/api/articles',methods=['GET'])

defget_articles():

""" 获取所有文章列表 """

returnjsonify({'articles':articles})

@app.route('/blog/api/articles/',methods=['GET'])

defget_article(article_id):

""" 获取某篇文章 """

article=filter(lambdaa:a['id']==article_id,articles)

iflen(article)==:

abort(404)

returnjsonify({'article':article[]})

@app.errorhandler(404)

defnot_found(error):

returnmake_response(jsonify({'error':'Not found'}),404)

if__name__=='__main__':

app.run(host='127.0.0.1',port=5632,debug=True)

将上面的代码保存为文件 app.py,通过 python app.py 启动这个 Web Service。

接下来,我们进行测试。这里,我们采用命令行语句 curl 进行测试。

开启终端,敲入如下命令进行测试:

$curl-ihttp://localhost:5632/blog/api/articles

HTTP/1.0200OK

Content-Type:application/json

Content-Length:224

Server:Werkzeug/0.11.4Python/2.7.11

Date:Tue,16Aug201615:21:45GMT

{

"articles":[

{

"content":"tuple, list, dict",

"id":1,

"title":"the way to python"

},

{

"content":"GET, POST, PUT",

"id":2,

"title":"the way to REST"

}

]

}

$curl-ihttp://localhost:5632/blog/api/articles/2

HTTP/1.0200OK

Content-Type:application/json

Content-Length:101

Server:Werkzeug/0.11.4Python/2.7.11

Date:Wed,17Aug201602:37:48GMT

{

"article":{

"content":"GET, POST, PUT",

"id":2,

"title":"the way to REST"

}

}

$curl-ihttp://localhost:5632/blog/api/articles/3

HTTP/1.0404NOTFOUND

Content-Type:application/json

Content-Length:26

Server:Werkzeug/0.11.4Python/2.7.11

Date:Wed,17Aug201602:32:10GMT

{

"error":"Not found"

}

上面,我们分别测试了『获取所有文章列表』、『获取某篇文章』和『获取不存在的文章』这三个功能,结果也正是我们所预料的。

POST 方法

下面我们使用 POST 方法创建一个新的资源。在上面的代码中添加以下代码:

fromflaskimportrequest

@app.route('/blog/api/articles',methods=['POST'])

defcreate_article():

ifnotrequest.jsonornot'title'inrequest.json:

abort(400)

article={

'id':articles[-1]['id']+1,

'title':request.json['title'],

}

articles.append(article)

returnjsonify({'article':article}),201

测试如下:

$curl-i-H"Content-Type: application/json"-XPOST-d'{"title":"the way to java"}'http://localhost:5632/blog/api/articles

HTTP/1.0201CREATED

Content-Type:application/json

Content-Length:87

Server:Werkzeug/0.11.4Python/2.7.11

Date:Wed,17Aug201603:07:14GMT

{

"article":{

"content":"",

"id":3,

"title":"the way to java"

}

}

可以看到,创建一篇新的文章也是很简单的。request.json 保存了请求中的 JSON 格式的数据。如果请求中没有数据,或者数据中没有 title 的内容,我们将会返回一个 “Bad Request” 的 400 错误。如果数据合法(必须要有 title 的字段),我们就会创建一篇新的文章。

PUT 方法

下面我们使用 PUT 方法更新文章,继续添加代码:

@app.route('/blog/api/articles/',methods=['PUT'])

defupdate_article(article_id):

article=filter(lambdaa:a['id']==article_id,articles)

iflen(article)==:

abort(404)

ifnotrequest.json:

abort(400)

returnjsonify({'article':article[]})

测试如下:

$curl-i-H"Content-Type: application/json"-XPUT-d'{"content": "hello, rest"}'http://localhost:5632/blog/api/articles/2

HTTP/1.0200OK

Content-Type:application/json

Content-Length:98

Server:Werkzeug/0.11.4Python/2.7.11

Date:Wed,17Aug201603:44:09GMT

{

"article":{

"content":"hello, rest",

"id":2,

"title":"the way to REST"

}

}

可以看到,更新文章也是很简单的,上面我们更新了第 2 篇文章的内容。

DELETE 方法

下面我们使用 DELETE 方法删除文章,继续添加代码:

@app.route('/blog/api/articles/',methods=['DELETE'])

defdelete_article(article_id):

article=filter(lambdat:t['id']==article_id,articles)

iflen(article)==:

abort(404)

articles.remove(article[])

returnjsonify({'result':True})

测试如下:

$curl-i-H"Content-Type: application/json"-XDELETEhttp://localhost:5632/blog/api/articles/2

HTTP/1.0200OK

Content-Type:application/json

Content-Length:20

Server:Werkzeug/0.11.4Python/2.7.11

Date:Wed,17Aug201603:46:04GMT

{

"result":true

}

$curl-ihttp://localhost:5632/blog/api/articles

HTTP/1.0200OK

Content-Type:application/json

Content-Length:125

Server:Werkzeug/0.11.4Python/2.7.11

Date:Wed,17Aug201603:46:09GMT

{

"articles":[

{

"content":"tuple, list, dict",

"id":1,

"title":"the way to python"

}

]

}

附录

常见 HTTP 状态码

HTTP 状态码主要有以下几类:

1xx —— 元数据

2xx —— 正确的响应

3xx —— 重定向

4xx —— 客户端错误

5xx —— 服务端错误

常见的 HTTP 状态码可见以下表格:

curl 命令参考

完整代码

本文的完整代码可在 Gist 查看(https://gist.github.com/ethan-funny/cf19aa89175055de6517d851759ad743)。

参考链接

理解本真的REST架构风格

基于 Flask 实现 RESTful API | Ross’s Page

(译)使用Flask实现RESTful API – nummy的专栏 – SegmentFault

怎样用通俗的语言解释什么叫 REST,以及什么是 RESTful? – 知乎

What Does RESTful Really Mean? – DZone Integration

HTTP状态码 – 维基百科,自由的百科全书

理解RESTful架构 – 阮一峰的网络日志

来源:FunHacks

funhacks.net/2016/08/21/restful_api_with_flask/

Python开发整理发布,转载请联系作者获得授权

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180128B0HYXR00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券