Day 28 Flask-RESTX

看到标题上的 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="[email protected]"),
    '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 时也很方便,能够当成技术文件的同时,也避免了没有即时更新的问题(话说我本来想偷懒不装资料库的,但我怎麽好像反而花了更多功夫呢?)。

大家掰~掰~


<<:  D31 - 「来互相伤害啊!」:无聊我要见到血流成河

>>:  D32 - 完赛心得

{DAY 23} Pandas 学习笔记part.9

前言 这篇文章想学习的主题是常见的资料分析函数 前一篇学到了利用groupby.() 搭配聚合函数进...

成衣裁剪计划

前一篇的裁剪计划使用Excel设计, 现已将其系统化, 由系统安排裁剪计划并开立开裁通知单 不习惯看...

第10-2章:监控与管理作业系统上之程序(二)

前言 在上一章节中,讲述了Linux process之基本原理与机制,以及控制jobs工作的方法,并...

第二十六天:UI切版 & 元件-图文资讯元件、ICON字型 & SVG、通知讯息元件

今天的内容 一、图文资讯元件 二、ICON: Webfont & SVG 三、通知讯息元件 ...

Day07 测试写起乃- let、let!、subject

昨天介绍了 before 之後今天就可以直接来看 let 搂! let、let! let =>...