iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0

看到標題上的 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 ,那就來看看如何使用吧。

Flask-RESTX 使用

要使用之前,當然是先安裝啦。安裝方式依然是透過熟悉的 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 時也很方便,能夠當成技術文件的同時,也避免了沒有即時更新的問題(話說我本來想偷懶不裝資料庫的,但我怎麼好像反而花了更多功夫呢?)。

大家掰~掰~


上一篇
Day 27 Celery
下一篇
Day 29 Unittest
系列文
月光下的Flask之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
jiamingla
iT邦新手 4 級 ‧ 2022-04-03 00:31:50

最後一個檔案應該是api.py?

shadow_gold iT邦研究生 2 級 ‧ 2022-04-03 11:52:22 檢舉

是的,感謝您的指正,希望這系列文章能夠幫助到您。

2
jiamingla
iT邦新手 4 級 ‧ 2022-04-14 02:14:01

目前寫restx好像只有這篇qq
好奇Email這個欄位restx有什麼樣方法用正則表達式之類的去驗證Email是否正確?

後來我發現
'email': fields.String(required=True, description='The user name', pattern='\S+@\S+.\S+')

這樣填就可以了!

shadow_gold iT邦研究生 2 級 ‧ 2022-04-14 12:33:11 檢舉

感謝您的回饋,希望這系列文章能夠幫助到您。

我要留言

立即登入留言