1. 程式人生 > >RESTful 和flask-restful的筆記

RESTful 和flask-restful的筆記

前後端分離簡單理解

flask中返回json格式資料

from flask import jsonify
# 返回json資料
@app.route('/')
def hello_world():
    data = {
        'msg': 'ok',
        'status': '200',
    }
    return jsonify(data)

簡單前後端分離:

前端頁面變成一個靜態檔案。存放在專案的static/html目錄下:

​
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Score List</title>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script>
        $(function (){
            $.getJSON("/getscores/", function (data){
                console.log(data);
                var scores = data["scores"];
                var $ul = $("#score_container");
                for(var i=0; i < scores.length; i++){
                    var $li = $("<li></li>").html(scores[i]);
                    $ul.append($li);
                }
            })
        })
    </script>
</head>
<body>
<h2>機試成績表</h2>
<ul id="score_container"></ul>
</body>
</html>

後端只需要返回json資料即可:

@app.route('/getscores/')
def get_scores():
    data = {
        'msg': 'ok',
        'status': '200',
        'scores': [1,2,3,4,5,6,30,40]
    }
    return jsonify(data)

什麼是RESTFul?

  1. 簡介

    REST即表述性狀態傳遞(英文:Representational State Transfer,簡稱REST)是Roy Fielding博士在2000年他的博士論文中提出來的一種軟體架構風格。它是一種針對網路應用的設計和開發方式,可以降低開發的複雜性,提高系統的可伸縮性。
    ​
    一種軟體架構風格、設計風格,而不是標準,只是提供了一組設計原則和約束條件。它主要用於客戶端和伺服器互動類的軟體。基於這個風格設計的軟體可以更簡潔,更有層次,更易於實現快取等機制。
    ​
    REST 指的是一組架構約束條件和原則。滿足這些約束條件和原則的應用程式或設計就是 RESTful。遵循restful開發的應用程式介面(API)稱為RESTFul API。
    ​
    RESTFul的介面都是圍繞資源以及對資源的各種動作展開的。
  2. 資源

    所謂的資源就是在網路中存在的任意實體,哪怕是一條簡單資訊。
  3. 動作

    所謂動作就是資料的CURD。在開發者設計良好的前提下,對網路資源的動作都可抽象為對資源的CURD操作。RESTFul對網路的操作抽象為HTTP的GET、POST、PUT、DELETE等請求的方式以完成對資源的增刪改查。具體對照如下:
    方法 行為 示例
    GET 獲取資源資訊 http://127.0.0.1:5000/source
    GET 獲取指定資源 http://127.0.0.1:5000/source/250
    POST 建立新的資源 http://127.0.0.1:5000/source
    PUT 更新指定資源 http://127.0.0.1:5000/source/250
    DELETE 刪除指定資源 http://127.0.0.1:5000/source/250
  4. 資料

    通常傳輸的資料格式都採用JSON,有時也可以通過URL的引數進行傳遞
  5. 工具

    說明:postman是一款非常好用的API開發測試工具,可以模擬各種請求
    提醒:安裝包,一路next完成安裝,演示一個地址的訪問

參考阮一峰大神的部落格:http://www.ruanyifeng.com/blog/2011/09/restful.html

理解之後再來看RESTful api開發遵循的原則:http://www.ruanyifeng.com/blog/2014/05/restful_api.html

假如獲取電影資源,遵循RESTful api開發原則的程式碼應該怎麼寫:

@app.route('/movie/', methods=["GET", "POST", "PUT", "DELETE"])
def movie():
    if request.method == "GET":
        # 獲取資源
        data = {
            "m_name": "捉妖記"
        }
        return jsonify(data)
    elif request.method == "POST":
        data = {
            "msg": "儲存成功"
        }
        return jsonify(data)
    elif request.method == "PUT":
        data = {
            "msg": "更新成功"
        }
        return jsonify(data)
    elif request.method == "DELETE":
        data = {
            "msg": "刪除成功"
        }
        return jsonify(data)
    else:
        abort(405)

原生實現RESTful

定義一個user模型

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    u_name = db.Column(db.String(16), unique=True)
    u_password = db.Column(db.String(32))
​
    def to_dict(self):
        return {"u_name": self.u_name, 'u_password': self.u_password}

實現原生RESTful:

@blue.route("/users/<int:id>/", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
def users(id):
    if request.method == "GET":
        page = int(request.args.get("page", default=1))
        per_page = int(request.args.get("per_page", default=3))
​
        users = User.query.paginate(page=page, per_page=per_page, error_out=False).items
        users_dict = []
        for user in users:
            users_dict.append(user.to_dict())
​
        data = {
            "message": "ok",
            "status": "200",
            "data": users_dict
        }
​
        return jsonify(data)
​
    elif request.method == "POST":
        # 更新或建立
        username = request.form.get("username")
        password = request.form.get("password")
​
        data = {
            "message": "ok",
            "status": "422"
        }
​
        if not username or not password:
            data["message"] = "引數不正確"
            return jsonify(data), 422
​
        user = User()
        user.u_name = username
        user.u_password = generate_password(password=password)
​
        try:
​
            db.session.add(user)
            db.session.commit()
            data["status"] = "201"
        except Exception as e:
            data["status"] = "901"
            data["message"] = str(e)
            return jsonify(data), 422
​
        return jsonify(data), 201
​
    elif request.method == "PUT":
        username = request.form.get("username")
        password = request.form.get("password")
        user = User.query.get(id)
​
        user.u_name = username
        user.u_password = generate_password(password)
​
        db.session.add(user)
        db.session.commit()
​
        data = {
            "message": "update success",
        }
​
        return jsonify(data), 201
​
    elif request.method == "DELETE":
        user = User.query.get(id)
​
        data = {
            "message": "delete success"
        }
​
        if user:
            db.session.delete(user)
            db.session.commit()
            return jsonify(data), 204
        else:
            data["message"] = "指定資料不存在"
            return jsonify(data)
    elif request.method == "PATCH":
        password = request.form.get("password")
        user = User.query.get(id)
        user.u_password = generate_password(password)
​
        data = {
            "messgage": "update success"
        }
​
        db.session.add(user)
        db.session.commit()
​
        return jsonify(data), 201
    else:
        abort(405)
​
​
def generate_password(password):
    hash = hashlib.md5()
    hash.update(password.encode("utf-8"))
    return hash.hexdigest()

前端只需要根據ajax的方法型別來控制對資源的操作:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>UserLogin</title>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script type="text/javascript">
​
        $(function () {
​
                $("button").click(function () {
​
                    var username = $("#username").val();
                    var password = $("#password").val();
​
                    $.ajax("/users/5/", {
​
                        datatype: "json",
                        type: "PATCH",
                        data: "username=" + username + "&password=" + password,
​
                        success: function (data) {
                            console.log(data);
                        }
                    })
​
                })
            }
        )
​
    </script>
</head>
<body>
​
<span>使用者名稱:</span><input id="username" type="text" placeholder="請輸入使用者名稱">
<br>
<span>密碼:</span> <input id="password" type="password" placeholder="請輸入密碼">
<br>
<button>註冊</button>
​
</body>
</html>

使用Flask-restful

flask-restuflu中每種資源抽象成類,需要繼承自Resource,來看一個最簡單的例子,把我們的helloword轉化為一個資源:

class Hello(Resource):
​
    def get(self):
        return {"msg": "ok"}
​
    def post(self):
        return {"msg": "create success"}