01.12 基於 Flask 開發 RESTful API 的簡單向導

基於 Flask 開發 RESTful API 的簡單向導

寫在最前

  • 後臺編輯器對代碼塊的支持並不友好, 因此代碼塊大部分以圖片的形式展現, 最後可能會把代碼放到 github 上, 鏈接會在最後給出
  • 在篇文章的示例中,所有的 API 的返回都是 JSON
  • 使用到的擴展 flask-login/ flask-sqlalchemy/ flask-migrate
  • 第一次使用 flask 及其擴展,如文章中存在錯誤,請各位包涵,期待各位的指點

最簡單的app

基於 Flask 開發 RESTful API 的簡單向導

基於 Flask 開發 RESTful API 的簡單向導

  • 默認監聽的是 " 127.0.0.1:5000", 若想調整, 可以在run的時候加入參數 host 和 port

> app.run(host='0.0.0.0', port=8080)

...

* Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)

  • 最後部署項目的時候會用到 gunicorn, 通過 --bind 參數來調整

第一個 Blueprint

Blueprint 是用來管理一組相似視圖(理解為管理api)的方法, 例如

# 用戶API Blueprint

/api/users

/api/users/<user> /<user>

# 組API Blueprint

/api/groups

/api/groups/<group>

基於 Flask 開發 RESTful API 的簡單向導

index blueprint

app.py 調整為

基於 Flask 開發 RESTful API 的簡單向導

app.py

重新運行app.run()後, 在瀏覽器中輸入 http://localhost:5000, 會看到相應的輸出

基於 Flask 開發 RESTful API 的簡單向導

output

配置文件

  • 加載配置文件的方式有幾種,from_object/ from_envvar/ from_pyfile
  • 其中, from_envvar 會加載環境變量中指定的文件, 格式與 from_pyfile 相同, 路徑為相對(app.py)或者是絕對路徑
  • 我更傾向於使用 from_envvar/ from_pyfile 這種方式來加載配置文件,理由如下
    • 項目開發,一般會分為 開發環境/ 測試環境/ 生產環境,會有不同的配置文件
    • 由於配置文件中可能會存放數據庫連接信息,密鑰等敏感字段,因此,不建議將測試/ 生產環境的配置上傳到代碼服務器上
    • 理想的方式是通過配置中心服務來管理,但是配置中心服務不一定會有
    • 項目的開發及初期運維可能會是同一個人,因此,可以在配置測試/ 生產環境的服務器時,由開發人員將所需配置直接寫在相應的服務器上,通過環境變量的方式指定其路徑即可
    • 在使用 supervisor 來管理項目進程時,可以通過配置 environment 來實現
  • 最簡單的配置文件

# config.py

DEBUG = True


# app.py

...

加載配置文件

app.config.from_envvar('APP_CONFIG_FILE')

# 添加環境變量

> export APP_CONFIG_FILE="/yourpath/config.py"

# 或者在 supervisor 的配置文件中聲明

# environment=APP_CONFIG_FILE="/yourpath/config.py"

數據庫

  • 用到的擴展組件
    • flask-sqlalchemy: 基於ORM 框架 SQLAlchemy
    • flask-migrate: 管理數據模型,用於初始化,升級,降級等操作
  • 增加 ext.py, 用於定義(聲明)用到的擴展組件
基於 Flask 開發 RESTful API 的簡單向導

ext.py

  • 修改配置文件(使用 SQLite 來說明)

# config.py

...

SQLALCHEMY_DATABASE_URI = 'sqlite:///tutorial.db'

  • 若是使用 MySQL, 需要在配置文件中加入 SQLALCHEMY_POOL_RECYCLE = 3600, 會自動收回無用的數據庫連接, 如果不加這個配置, 連接會在 8 小時後斷開, 要重啟 app 才可以恢復(這是在第一次使用的時候碰到的問題, 由於服務器沒有關閉, 第二天一早在使用時, 出現了連接斷開的異常)
  • 修改 app.py

...

from ext import db, migrate

...

db.init_app(app)

migrate.init_app(app, db)

  • 增加數據模型
基於 Flask 開發 RESTful API 的簡單向導

base.py

基於 Flask 開發 RESTful API 的簡單向導

user.py

  • 初始化 migrate, 創建文件夾 migrations, 運行命令 flask db init, 這個時候查看數據庫, 是沒有User 表的, 因為通過 app.py 所引用的包中, 並沒有使用到 models.user.User, 這裡, 有幾種方式可以解決這個問題,
    • 一是, 先寫用到 models.user.User 的 Blueprint, 接著在 app.py 中註冊這個 Blueprint 即可
    • 二是, 臨時在 app.py 中導入, 在完成之後, 再刪除導入即可
    • 三是, 通過另外的管理腳本, 考慮到在初始化數據庫時可能會有其他的操作, 創建了 manage.py 這個文件
基於 Flask 開發 RESTful API 的簡單向導

manage.py

基於 Flask 開發 RESTful API 的簡單向導

manage.py

增加藍圖 users

  • 添加查詢所有用戶的api /api/users
基於 Flask 開發 RESTful API 的簡單向導

views/user.py

基於 Flask 開發 RESTful API 的簡單向導

views/__init__.py

  • 修改 app.py

# app.py

...

from views import index, user

...

app.register_blueprint(user.bp)

  • 瀏覽器中輸入 http://localhost:5000, 會看到返回結果如下
基於 Flask 開發 RESTful API 的簡單向導

配置登錄認證

  • 修改 models.user.User, 繼承 flask_login.UserMixin, 並重寫方法 get_id
基於 Flask 開發 RESTful API 的簡單向導

models.user.py

  • 修改配置文件 config.py, 增加 SECRET_KEY = 'yoursecretkey', 不建議用過於簡單的key, 官方推薦通過 os.urandom 來生成, 這裡可能有一個地方需要注意, 當服務部署為多進程時(使用 gunicorn), 千萬避免寫成如下形式, SECRET_KEY = os.urandom(16), 由於每個進程都會生成一個隨機數, 可能會導致需要用戶重複登錄, 這是個很愚蠢的錯誤, 由於我在開發時使用了 supervisor + gunicorn 來管理, 因此忘記了多進程的問題, 困惑了我好一會兒
  • 修改 app.py
基於 Flask 開發 RESTful API 的簡單向導

app.py

      • unauthorized 方法: 在用戶未登錄時, 會調用此方法
      • load_user_from_request 方法: 通過 Request 信息(header/ body/ ...)加載用戶, 有一點需要注意, 當 session 中存在用戶信息時(在 request cookie 中包含 session_id), 不會調用此方法
      • load_user 方法: 獲取當前登錄用戶的信息

增加藍圖 login


基於 Flask 開發 RESTful API 的簡單向導

views/login.py

  • 修改 app.py

...

from views import index, user, login

...

app.register_blueprint(login.bp)

  • 修改 views/users.py

...

from flask_login import login_required

...

@bp.route('')

@login_required

def list_users(): ...

  • 此時, 訪問 http://localhost:5000/api/users, 會返回 401 錯誤
基於 Flask 開發 RESTful API 的簡單向導

  • 登錄, 訪問 /api/sign/in
基於 Flask 開發 RESTful API 的簡單向導

  • 之後, 再次訪問 /api/users, 就正常了
  • 註銷, /api/sign/out, 之後, 訪問 /api/users 時, 就會返回 401
基於 Flask 開發 RESTful API 的簡單向導

  • 測試一下不登錄的情況下訪問 /api/users, 之前的 load_user_from_request 方法中, 有一句 if request.args.get('hack'): return User.query.get(1), 只要在請求上加上 ?hack=1, 就可以看到正常的結果
基於 Flask 開發 RESTful API 的簡單向導

未完待續

  • 通過 supervisor/ gunicorn/ nginx 來部署項目
  • gunicorn/ supervisor 的配置項

相關鏈接

  • flask 文檔: https://flask.palletsprojects.com/en/1.1.x/
  • flask_login 文檔: https://flask-login.readthedocs.io/en/latest/
  • flask_migrate 文檔: https://flask-migrate.readthedocs.io
  • flask_sqlalchemy 文檔: https://flask-sqlalchemy.palletsprojects.com/en/2.x/
  • 項目 Github 鏈接: https://github.com/liuxuange/flask_tutorial

鳴謝

  • 感謝在項目中幫助過我的人(抱歉, 不便透露真實姓名)


分享到:


相關文章: