看到標題上的 REST 四個英文字母,不知道有沒有令你想起了什麼?
對,就是 RESTful API 的那個 REST(Representational State Transfer,表現層狀態轉換),所以這個插件就是可以讓你輕鬆的產生 RESTful 型態的 API(對,這篇講得基本上都是關於 API 的東西)。
開始介紹它之前,我想先來說一下它的身世(為什麼我要說呢,因為我想提到另一個東西),剛開始是有一個叫做 Flask-RESTful 的插件。因為這個插件就只是普通的能夠產生 RESTful 的 API,雖然沒有什麼不好,但是如果要交接給其他人;或是要寫技術文件時,第一個念頭通常是 Word。雖然沒有不好,不過時間久了在維護時會常常會遇到沒有更新或是參數錯誤發生,這時候如果有一個東西,可以在更新程式的時候,自動生成相應的描述 API 的文件那就好了。
所以產生了後來的 Flask-RESTPlus ,這個是插件是以 Flask-RESTful 為基礎,增加了自動生成 Swagger 這種可以描述 API 的東西(我扯了這麼多,就是想講 Swagger 而已)。不過後來因為看似沒有被積極維護的原因,所以有些熱心的人就分支出了 Flask-RESTX 的版本。這就是它的身世,所以 Flask-RESTful 跟 Flask-RESTPlus 用法是大致相同的(目前是這樣啦,之後會不會大改不知道)。
那 Swagger 是什麼呢?根據維基百科的說明:
Swagger是一種接口描述語言。
好了,現在講完了 Flask-RESTX 以及提到了 Swagger ,那就來看看如何使用吧。
要使用之前,當然是先安裝啦。安裝方式依然是透過熟悉的 pip 安裝啦,然後依然開一個新的專案。
$ pipenv install flask-restx
然後改完後的架構長這樣:
ithome
├── apis
│ ├── __init__.py # 空的
│ └── api.py
├── base
│ └── __init__.py # 初始化
├── db # (假的)資料庫
│ └── __init__.py # 資料庫連線以及操作
├── app.py
├── config.py
├── Pipfile
└── Pipfile.lock
首先先來看一下資料庫吧(因為我前面沒有講到資料庫,以及我懶,所以我用已存在的 Redis 來假裝成一個資料庫)。
db/__init__.py
from redis import Redis
# 使用 Redis 假裝資料庫,並且使用 Redis 的 Hash 儲存
# name 相當於資料表,key 相當於主鍵(ID),value 相當於其他資料(帳號、密碼)
# 我只寫了有用到的幾個 function 而已,其他要用自己加
# 實際上線的服務不要這樣玩,還有密碼不要用明文存。
class Database:
redis_client = None
@classmethod
def initial(self):
self.redis_client = Redis(host='localhost', port=6379, db=2)
@classmethod
def insert(self, name, key, value):
self.redis_client.hsetnx(name, key, value)
@classmethod
def length(self, name):
return self.redis_client.hlen(name)
然後我們從程式入口開始看起。
app.py
from base import app
if __name__ == "__main__":
app.run()
為什麼只有一個路由?別急,我們開始往回找,接著看 base 做了什麼。
base/__init__.py
from flask import Flask
from flask_restx import Api
from apis.account.api import api as account_ns
import config
from db import Database
app = Flask(__name__, instance_relative_config=True)
app.config.from_object(config.DevelopmentConfig)
# 設定一個 API 核心(很爛,看不懂對吧,但我已經用盡我畢生的中文功力去形容了,將就一下吧)
# 第一個參數必須為 Flask 實體或是 Blueprint
# doc 為 Swagger 的路由位置
api = Api(app, version='0.0.1',
title='Flask-RESTX and Swagger test', doc='/api/doc')
# 加入名稱空間(跟上面同樣爛)
api.add_namespace(account_ns)
# 初始化資料庫
Database.initial()
是不是突然多了很多東西,好像都看不太懂對吧,沒關係,我們慢慢往回看。db 的看過了,那就接著來看一下有關 api 的東西(這邊考量到長度的關係,所以只做了一個註冊的 API)。
apis/api.py
from flask_restx import Namespace, fields, Resource
import ast
from db import Database as db
# 新增一個叫 account 的名稱空間
api = Namespace("account", description="帳號管理")
# ---------- 輸入輸出的格式 ----------
base_output_payload = api.model('基本輸出', {
'status': fields.String(required=True, default=0),
'message': fields.String(required=True, default="")
})
account_register_input_payload = api.model('註冊帳號input', {
'email': fields.String(required=True, example="test01@gmail.com"),
'password': fields.String(required=True, example="test")
})
account_register_output_payload = api.clone('註冊帳號output', base_output_payload)
# ---------- 路由以及功能 ----------
@api.route('/register')
class register(Resource):
@api.expect(account_register_input_payload)
@api.marshal_with(account_register_output_payload)
def post(self):
data = api.payload
try:
nums = str(db.length('users'))
data = str({'email': data['email'], 'password': data['password']})
db.insert('users', nums, data)
except Exception:
message = {'status': 1, 'message': 'error'}
else:
message = {'status': 0, 'message': ''}
finally:
return message
那麼程式的部分大概就這樣,接著我們來到瀏覽器看一下效果。
輸入 http://localhost:5000/api/doc
看看(因為有用到 Redis ,所以記得先啟動 redis-server 喔),如果都沒問題的話,應該會像這樣。
接著點一下 Try it out
再點下方的 Execute
看看,如果都正常的話,在更下方的 Response
-> Server response
裡面的 Response body
應該會出現像這樣的結果。
Flask-RESTful vs Flask-RESTplus
那麼就大概這樣,Flask-RESTX 是開發 RESTful API 很好用的插件;Swagger 在測試 API 時也很方便,能夠當成技術文件的同時,也避免了沒有即時更新的問題(話說我本來想偷懶不裝資料庫的,但我怎麼好像反而花了更多功夫呢?)。
大家掰~掰~
目前寫restx好像只有這篇qq
好奇Email這個欄位restx有什麼樣方法用正則表達式之類的去驗證Email是否正確?
後來我發現
'email': fields.String(required=True, description='The user name', pattern='\S+@\S+.\S+')
這樣填就可以了!
感謝您的回饋,希望這系列文章能夠幫助到您。