0. 前言
接下來一段時間,Gevin將開一個系列專題,講Flask RESTful API的開發,本文是第1篇《Flask RESTful 基礎》,本系列文章列表如下:
- 基礎篇(1) --- Flask RESTful 基礎
- 基礎篇(2) --- 一個簡單的Flask RESTful 例項
- To Be Continued...
1. RESTful 簡介
我在博文《RESTful 架構風格概述》和《RESTful API 編寫指南》中曾詳細論述過我對RESTful的理解,以及規範的RESTful API開發需要涉及的內容,本節摘錄幾條重點內容,為下文做鋪墊:
- RESTful 是面向資源的,每個資源至少有一個url與之對應
- 統一資料互動介面,即透過http的
GET
,POST
,PUT
(orPATCH
), 和DELETE
進行資源的獲取、建立、更新和刪除 - 資源(資料)以文字形式在網路上傳輸,通常以json或xml格式為載體
- 無狀態(以後講認證時再展開論述)
2. Flask 對RESTful 架構風格的支援
Flask RESTful 開發相關的庫很多,我也收集過一些(collection在此,不定期更新),其實,與Django不同,Flask原生對RESTful的支援已經做的很好,不借助這些extension,一樣可以開發出足夠好的RESTful API,而且沒有這些extension的束縛,我們可以在開發過程中,配合使用Flask生態中處理相應問題最好的extension,或者我們自己最上手的extension,這也更加符合Flask的philosophy。Gevin在Flask RESTful 開發中,不使用各類flask rest擴充套件的主要原因,正是每個擴充套件都有不盡如意之處。
那麼,我們就來看一下Flask原生是如何支援RESTful開發的。
(注:Django RESTful開發主要基於Django REST Framework,Django的DRF理念對我一直很受用,我在Flask開發和Flask RESTful API開發中,借鑑了很多Django的設計理念。因此,對於如何做好Flask開發,Gevin有個觀點是:不妨從Django的開發做起~ :P)
2.1 Flask對HTTP方法的支援
Flask原生支援所有的HTTP方法,如RESTful API中最常用的GET
, POST
, PUT
, PATCH
和DELETE
,這些不需贅述解釋,直接上程式碼即可:
@app.route('/http-method-test/', methods=['GET', 'POST', 'PUT', 'PATCH', 'DELETE'])
def http_method_example():
if request.method == 'GET':
return 'Send request with `GET` method'
elif request.method == 'POST':
return 'Send request with `POST` method'
elif request.method == 'PUT':
return 'Send request with `PUT` method'
elif request.method == 'PATCH':
return 'Send request with `PATCH` method'
elif request.method == 'DELETE':
return 'Send request with `DELETE` method'
另外一種方式是採用Flask的MethodView
:
class HttpMethodExample(MethodView):
def get(self):
return 'Send request with `GET` method'
def post(self):
return 'Send request with `POST` method'
def put(self):
return 'Send request with `PUT` method'
def patch(self):
return 'Send request with `PATCH` method'
def delete(self):
return 'Send request with `DELETE` method'
app.add_url_rule('/http-method-test2/', view_func=HttpMethodExample.as_view('http_method_example2'))
2.2 Flask 對序列化與反序列化的支援
RESTful 開發時,資料的載體通常為json
或xml
格式的文字,隨著RESTful的不斷髮展,json
更是成為了RESTful API 資料的主流載體。而Flask本身,已經對json的支援已經非常好了。
2.2.1 序列化
RESTful API開發中的序列化,透過包含了以下操作:
- 將Python native格式的資料(如dict和list)轉換為文字資料(如json或xml)
- 將文字資料作為請求的response返回給客戶端,response的http header裡要同時附加
application/json
這個mimetype
這兩步操作,Flask提供的一個快捷函式jsonify()
能直接完成,其詳情正如下面的Flask官方文件所述:
This function wraps dumps() to add a few enhancements that make life easier. It turns the JSON output into a Response object with the application/json mimetype. For convenience, it also converts multiple arguments into an array or multiple keyword arguments into a dict. This means that both jsonify(1,2,3) and jsonify([1,2,3]) serialize to [1,2,3].
很簡單的事情,不該說這麼多,直接上程式碼示例吧:
class SerializationExample(MethodView):
def get(self):
option = request.args.get('option')
if option == 'list1':
return self.test_list()
if option == 'list2':
return self.test_list2()
if option == 'dict1':
return self.test_dict1()
if option == 'dict2':
return self.test_dict2()
if option == 'dict3':
return self.test_dict3()
msg = {
'info': '`option` is needed in url as a url parameter',
'avilable option values': 'list1, list2, test_dict1, test_dict2, test_dict2'
}
return jsonify(msg)
def test_list(self):
data = [{'a':1, 'b':2}, {'c':3, 'd':4}]
return jsonify(result=data)
def test_list2(self):
data = [1,2,3,4,5,6,7,8]
return jsonify(data)
def test_dict1(self):
data = {'a':1, 'b':2, 'c':3}
return jsonify(data)
def test_dict2(self):
data = {'a':1, 'b':2, 'c':3}
return jsonify(**data)
def test_dict3(self):
data = {'a':1, 'b':2, 'c':3}
return jsonify(result=data)
app.add_url_rule('/serialization/', view_func=SerializationExample.as_view('serialization'))
上面程式碼的重點即,那幾個以test_
開頭的函式,序列化的表現形式無外乎這幾種。
2.2.2 反序列化
反序列化,即把文字形式的資料轉換為Python native型別資料的過程。在RESTful API開發時,Flask內建的get_json()
方法,能夠把request中的json資料,轉換為Python標準庫中的dict或list。
Parses the incoming JSON request data and returns it. By default this function will return None if the mimetype is not
application/json
, but this can be overridden by the force parameter.If parsing fails the
on_json_loading_failed()
method on the request object will be invoked.
示例程式碼:
@app.route('/deserialization/', methods=['get', 'post'])
def deserialization():
if request.method == 'POST':
data = request.get_json()
if not data:
return 'No json data found', 400
result = {
'json data in request': data
}
return jsonify(result)
return 'Please post json data'
注:
Flask原生的序列化和反序列化方法,都是針對目前RESTful API 開發時最流行的json格式的,且只能做json
與dict
或list
的相互轉換,如果想序列化或反序列化物件例項,需要藉助其他方法,這個會在以後的文章中做進一步解釋。
3. What's More
我在GitHub上的專案restapi_example,存放了本系列內容的完整原始碼,大家可以隨意查閱。
本章涉及的程式碼,完整示例請檢視上面專案的
chapter1
分支RESTful API 開發時,測試API可用工具Postman
下一講預告:Gevin將結合一個具體的應用例項,介紹RESTful API的設計與實現
注:轉載本文,請與Gevin聯絡
歡迎關注我的微信公眾賬號