06-Flask之REST&API設(shè)計

一考杉、REST

  • 問題

網(wǎng)絡(luò)應(yīng)用程序,分為前端和后端兩個部分舰始。當(dāng)前的發(fā)展趨勢崇棠,就是前端設(shè)備層出不窮(手機、平板丸卷、桌面電腦枕稀、其他專用設(shè)備......)。

因此谜嫉,必須有一種統(tǒng)一的機制萎坷,方便不同的前端設(shè)備與后端進行通信。這致使API構(gòu)架的流行骄恶。

  • 基本概念

REST是"Representational State Transfer"縮寫食铐,即是"表現(xiàn)層狀態(tài)轉(zhuǎn)化"。而"表現(xiàn)層"其實指的是"資源(Resource)"的表現(xiàn)層僧鲁。

一種軟件架構(gòu)風(fēng)格虐呻、設(shè)計風(fēng)格、而不是標準寞秃,只是提供了一組設(shè)計原則和約束條件斟叼。

它主要用于客戶端和服務(wù)器交互類的軟件〈菏伲基于這個風(fēng)格設(shè)計的軟件可以更簡潔朗涩,更有層次,更易于實現(xiàn)緩存機制等绑改。

REST其實是一種組織Web服務(wù)的架構(gòu)谢床,而并不是我們想象的那樣是實現(xiàn)Web服務(wù)的一種新的技術(shù),更沒有要求一定要使用HTTP厘线。其目標是為了創(chuàng)建具有良好擴展性的分布式系統(tǒng)识腿。

1\. 資源(Resource)
    就是網(wǎng)絡(luò)上的一個實體,或是網(wǎng)絡(luò)上的具體信息造壮,可以是一段文本渡讼、一張圖片、一首歌曲、一部電影成箫。
    每個資源都會對應(yīng)的URL展箱,且是唯一的標識符,想要獲取資源只需要調(diào)用對應(yīng)URL蹬昌。
2\. 表現(xiàn)層(Representation)
    "資源"是一種信息實體混驰,它可以有多種外在表現(xiàn)形式。
    而"資源"具體呈現(xiàn)出來的形式皂贩,就叫它的"表現(xiàn)層"账胧。
3\. 狀態(tài)轉(zhuǎn)換(State Transfer)
    訪問一個網(wǎng)站,就是客戶端和服務(wù)端的交互過程先紫,這個過程中就會涉及到數(shù)據(jù)和狀態(tài)的變化治泥。
    互聯(lián)網(wǎng)通信協(xié)議HTPP,是無狀態(tài)協(xié)議遮精。即所有狀態(tài)都保存在服務(wù)端居夹。
    客戶端要操作服務(wù)端必須通過某種方式,讓服務(wù)端發(fā)生"狀態(tài)轉(zhuǎn)換"本冲,而這轉(zhuǎn)換是建立在表現(xiàn)層之上的准脂,所以就是"表現(xiàn)層狀態(tài)轉(zhuǎn)換"。
    客戶端用到的手段只能是HTTP協(xié)議檬洞,在操作方式的動詞:     GET/POST/PUT/DELETE狸膏。
    對應(yīng)GET獲取資源,POST新建資源(或更新資源)添怔,PUT更新資源湾戳,DELETE刪除資源。

  • 架構(gòu)級約束
1.使用客戶/服務(wù)器模型广料±裕客戶和服務(wù)器之間通過一個統(tǒng)一的接口來互相通訊
2.層次化的系統(tǒng)。在一個REST系統(tǒng)中艾杏,客戶端并不會固定地與一個服務(wù)器打交道
3.無狀態(tài)韧衣。在一個REST系統(tǒng)中,服務(wù)端并不會保存有關(guān)客戶的任何狀態(tài)购桑。也就是說畅铭,客戶端自身負責(zé)用戶狀態(tài)的維持,并在每次發(fā)送請求時都需要提供足夠的信息
4.可緩存勃蜘。REST系統(tǒng)需要能夠恰當(dāng)?shù)鼐彺嬲埱笏敦员M量減少服務(wù)端和客戶端之間的信息傳輸,以提高性能
5.統(tǒng)一的接口元旬。一個REST系統(tǒng)需要使用一個統(tǒng)一的接口來完成子系統(tǒng)之間以及服務(wù)與用戶之間的交互榴徐。這使得REST系統(tǒng)中的各個子系統(tǒng)可以獨自完成演化

一個系統(tǒng)滿足了上面所列出的五條約束,那么該系統(tǒng)就被稱為是RESTful匀归。

  • 什么是RESTful框架
1\. 每一個URL代表一種資源
2\. 客戶端和服務(wù)器之間坑资,傳遞這種資源的某種表現(xiàn)層
3\. 客戶端通過四個HTTP動詞,對服務(wù)端進行操作穆端,實現(xiàn)"表現(xiàn)層狀態(tài)轉(zhuǎn)換"

RESTful API是目前比較成熟的一套互聯(lián)網(wǎng)應(yīng)用程序的API設(shè)計理論袱贮。

二、返回JSON格式數(shù)據(jù)

天氣API: https://www.sojson.com/api/weather.html

  • jsonify序列化操作
# 返回json格式數(shù)據(jù)
@blue.route('/getjson/')
def getjson():
    data = {
        'data': 'hello flask',
        'status': 200
    }
    return jsonify(data)

實現(xiàn)前后端的分離体啰,后臺人員只需要提供API接口接口攒巍。

  • 后臺人員工作職責(zé)
- 定制接口
- 模型定制
- 面向接口編程
    只關(guān)注請求地址
    值關(guān)注請求結(jié)果格式

  • 示例
- 在app/views.py中添加獲取商品列表數(shù)據(jù)API 【后臺人員】
    # 學(xué)生成績API
    @blue.route('/getscore/')
    def getscore():
        data = {
            'msg':'學(xué)生成績列表',
            'status': '200',
            'content': [20,32,53,90,43,67,99,89]
        }

        return jsonify(data)

    備注: 獲取數(shù)據(jù) http://127.0.0.1:8000/getscore/

- 在app/static/html/testlist.html       【前端人員】
    # 發(fā)起Ajax請求,獲取對應(yīng)學(xué)生成績列表json數(shù)據(jù)荒勇,解析json數(shù)據(jù)柒莉,并渲染到頁面中
    <script>
        $(function () {
            $.getJSON("http://127.0.0.1:8000/getscore/", function(json){
                if (json.status == 200){
                    $('body').append($('<h3></h3>').html(json.msg))

                    for(var i=0; i<json.content.length; i++){
                        $('body').append($('<h3></h3>').html('成績:'+json.content[i]))
                    }
                }
                else{
                    $('body').append($('<h3></h3>').html('哥們,你錯了!'))
                }
            });
        })
    </script>

    備注: 靜態(tài)頁面在瀏覽器中打開 http://127.0.0.1:8000/static/html/scorelist.html

書寫靜態(tài)頁面時沽翔,要注意是web相關(guān)的內(nèi)容兢孝,而不是模板,所以注釋等方式是會不一樣的=鲑恕?缧贰!

三橘沥、RESTful API設(shè)計

  • 協(xié)議
API與用戶的通信協(xié)議窗轩,通常使用HTTP(S)協(xié)議。

  • 域名
應(yīng)該盡量將API部署在專用域名之下座咆。
    如: http://api.zyz.com

如果確定API很簡單痢艺,不會有大規(guī)模擴從,可以考慮放在主域名之下介陶。
    如: http://www.zyz.com/api/

  • 版本
應(yīng)該將API的版本號放入URL腹备。
    如: http://api.zyz.com/v1/

也有將版本號放在HTTP的頭信息中,但不如放在URL中方便直觀斤蔓,Github就是這么做的植酥。

  • 路徑
路徑又稱"終點"(endpoint),表示API的具體網(wǎng)址弦牡。
在RESTful架構(gòu)中友驮,每個網(wǎng)址代表一種資源,所以網(wǎng)址不能有動詞驾锰,只能有名詞卸留。
而所用名詞往往與數(shù)據(jù)庫表單名對應(yīng)。

  • HTTP動詞
對于資源的具體操作類型椭豫,由HTTP動詞表示耻瑟。
HTTP常用動詞:
    - GET(SELECT) 從服務(wù)器取資源
    - POST(CREATE or UPDATE) 服務(wù)器中創(chuàng)建資源或更新資源
    - PUT(UPDATE) 在服務(wù)器更新資源(客戶端提供改變后的完整資源)
    - PATCH(UPDATE) 在服務(wù)器更新資源(客戶端提供改變的屬性)
    - DELETE(DELETE) 從服務(wù)器刪除資源
    - HEAD 獲取資源的元數(shù)據(jù)
    - OPTHONS 獲取信息旨指,關(guān)于資源的那些屬性是客戶端可以改變的

例如:
    - GET  /students  獲取所有學(xué)生
    - POST /student   新建學(xué)生
    - GET  /students/id 獲取某一個學(xué)生
    - PUT  /students/id 更新某個學(xué)生的信息(需要提供學(xué)生的全部信息)
    - PATHC /students/id 更新某個學(xué)生的信息(需要提供學(xué)生變更信息)
    - DELETE /students/id 刪除某個學(xué)生

  • 過濾信息
當(dāng)記錄數(shù)量過多,服務(wù)器不可能將它們返回給用戶喳整。APIT應(yīng)該提供參數(shù)谆构,過濾返回結(jié)果。
    ?limit=10
    ?offset=10
    ?page=2&per_page=10
    ?sortby=name&order=desc
    ?student_id=id

  • 狀態(tài)碼
服務(wù)器向用戶返回的狀態(tài)碼和提示信息框都。
    200 OK - [GET]:服務(wù)器成功返回用戶請求的數(shù)據(jù)
    201 CREATED -[POST/PUT/PATCH]:用戶新建或修改數(shù)據(jù)成功
    202 Accepted - [*] :表示一個請求已經(jīng)進入后臺排隊(異步任務(wù))
    204 NO CONTENT - [DELETE]:表示數(shù)據(jù)刪除成功
    400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發(fā)出的請求有錯誤
    401 Unauthorized - [*] :表示用戶沒有權(quán)限(令牌搬素,用戶名,密碼錯誤)
    403 Forbidden - [*]:表示用戶得到授權(quán)魏保,但是訪問是被禁止的
    404 NOT FOUND - [*]:用戶發(fā)出的請求針對的是不存在的記錄
    406 Not Acceptable - [*]:用戶請求格式不可得
    410 Gone - [GET] :用戶請求的資源被永久移除熬尺,且不會再得到的
    422 Unprocesable entity -[POST/PUT/PATCH]:當(dāng)創(chuàng)建一個對象時,發(fā)生一個驗證錯誤
    500 INTERNAL SERVER EROR - [*] :服務(wù)器內(nèi)部發(fā)生錯誤

    2xx —— 正確的響應(yīng)
    3xx —— 重定向
    4xx —— 客戶端錯誤
    5xx —— 服務(wù)端錯誤

  • 錯誤處理
如果狀態(tài)碼是4xx谓罗,就應(yīng)該向用戶返回出錯信息粱哼。一般來說,返回的信息中將error做為鍵名

  • 返回結(jié)果
針對不同操作檩咱,服務(wù)器想用戶返回的結(jié)果應(yīng)該符合以下規(guī)范:
    GET /collection:返回資源對象的列表(數(shù)組皂吮,集合)
    GET /collection/id:返回單個資源對象
    POST /collection:返回新生成的資源對象
    PUT /collection/id:返回完整的資源對象
    PATCH /collection/id:返回完整的資源對象
    DELETE /collection/id:返回一個空文檔

  • 核心點
RESTfull 的核心是 resource ,對一個 resource 税手,用不同的 HTTP verb 做增刪查改蜂筹。

  • 其他
服務(wù)器返回的數(shù)據(jù)格式,應(yīng)該盡量使用JSON

  • 原生實現(xiàn)
@blue.route('/api/v1/users/',methods=['GET','POST','DELETE','PUT','PATCH'])
def users():
    if request.method == 'GET': # 獲取用戶
        pass
    elif request.method == 'POST':  # 更新或創(chuàng)建用戶密碼
        # 獲取數(shù)據(jù)
        username = request.form.get('username')
        password = request.form.get('password')

        data = {
            'msg':'ok',
            'status': 201
        }

        # 不為空
        if not username or not password:
            data['msg'] = '參數(shù)不正確'
            data['status'] = 422
            return jsonify(data)

        user = User()
        user.u_name = username
        user.u_passwd = generate_passwd(password)

        try:
            db.session.add(user)
            db.session.commit()
        except Exception as e:
            data['msg'] = '用戶已存在'
            data['status'] = 423
            return jsonify(data)

        return jsonify(data)

    elif request.method == 'DELETE':    # 刪除用戶
        pass
    elif request.method == 'PUT':   # 更新賬和密碼
        pass
    elif request.method == 'PATCH':  # 修改密碼
        pass
    else:
        abort(405)

# 密碼加密處理
def generate_passwd(passwd):
    hash = hashlib.md5()
    hash.update(passwd.encode('utf-8'))
    return hash.hexdigest()

jsonify: json序列化

四芦倒、Flask-RESTful插件

Flask-RESTful添加快速構(gòu)建REST API的支持艺挪,也是一個能夠和現(xiàn)有ORM庫協(xié)同工作的輕量級的擴展。Flask-RESTful鼓勵以最小的設(shè)置的最佳實踐兵扬。

中文文檔: http://www.pythondoc.com/Flask-RESTful/

  • 基本使用
- 安裝
    pip install flask-restful

- 配置
    # ext.py文件中
    from flask_restful import Api
    api = Api()
    api.init_app(app)

- 使用(項目拆分)
    # 定義一個資源
    # views.py已經(jīng)可以替換為apis.py麻裳,之前的路由功能換種寫法
    class HelloWorld(Resource):
        def get(self):  # get請求
            return {'msg': 'hello world'}

        def post(self): # post請求
            return {'msg': '你好!'}

    # 添加一個資源
    # add_resource 注冊路由到框架上
    # 如果沒有指定 endpoint,F(xiàn)lask-RESTful 會根據(jù)類名生成一個
    # 但有時候如 url_for 需要 endpoint器钟,因此最好明確給 endpoint 賦值
    api.add_resource(HelloWorld, '/hello/',endpoint='hello')

Flask-Rest-JSONAPI插件津坑、Flask-Restless插件

  • 項目拆分
備注:
    之前路由的操作都是在views.py中,現(xiàn)在只需要提供API接口傲霸,所以功能就會不一樣疆瑰;
    在項目進行完基本拆分之后,可以將views.py改為apis.py昙啄;
    資源不止一個穆役,而不能都只是有一個,而是有多個梳凛,為了方便管理耿币,可以將apis變?yōu)榘男问剑奖愎芾?

# App/apis/__init__.py
  api = Api()
  def init_api(app):
        api.init_app(api)

# App/__init_.py [之前init_blue 換為 init_api即可]
  init_api(app)

# App/apis/HelloResource.py 定義資源
    class HelloWorld(Resource):
        def get(self):  # get請求
            return {'msg': 'hello world'}

# App/apis/__init__.py 添加資源
api.add_resource(HelloResource, '/hello/', endpoint='hello')

  • 帶參數(shù)操作
# App/apis/UserApi.py文件
class UserResource(Resource):
    def get(self,id):
        str = '(get)userid: %d' % id
        return {'msg':str}

    def post(self,id):
        str = '(post)userid: %d' % id
        return {'msg': str}

# App/apis/__init__.py文件
from App.apis import UserAPI
api.add_resource(UserResource, '/user/<int:id>/', endpoint='user')

Flask-RESTful 提供的最主要的基礎(chǔ)就是資源(resources)韧拒。資源(Resources)是構(gòu)建在 Flask視圖 之上淹接,只要在你的資源(resource)上定義方法就能夠容易地訪問多個 HTTP 方法十性。[無需原生操作,因為一個資源而進行不同的判斷操作處理]

  • 端點操作(Endpoints)
很多時候在一個 API 中塑悼,你的資源可以通過多個 URL 訪問劲适。
你可以把多個 URL 傳給 Api 對象的 Api.add_resource() 方法。每一個 URL 都能訪問到你的 Resource拢肆。
api.add_resource(HelloWorld, 
                 '/hello/',
                 '/haha/',
                 '/hehe/')

  • 輸出格式定制
默認情況下,在你的返回迭代中所有字段將會原樣呈現(xiàn)靖诗。
實際更多的需要一個字典類型數(shù)據(jù)郭怪,之后通過JSON序列化即可。
Flask-RESTful 提供了 fields 模塊和 marshal_with() 裝飾器來進行數(shù)據(jù)格式化刊橘。

# @marshal_with(需要返回的數(shù)據(jù)格式)
    如果返回的數(shù)據(jù)鄙才,在預(yù)定義的結(jié)構(gòu)中不存在,數(shù)據(jù)會被自動濾掉促绵;
    如果返回的數(shù)據(jù)攒庵,在預(yù)定的結(jié)構(gòu)中存在,數(shù)據(jù)會正常返回败晴;
    如果返回的數(shù)據(jù)比預(yù)定的結(jié)構(gòu)字段少浓冒,預(yù)定義的字段會顯示默認值;

# 支持類型
    - 常用基本類型
        String
        Integer
    - 列表類型
        List
    - 級聯(lián)類型
        Nested
    - 結(jié)構(gòu)嵌套
        fields.List(fields.Nested())

# 示例1
    """ 獲取一只貓的數(shù)據(jù)基本結(jié)構(gòu)
        {
            'msg':'ok',
            'status':200,
            'data': {
                'id': 1,
                'name': 'TOM',
                'color': '紅色'
            }
        }
    """
    catmodel_fields = {
        'id': fields.Integer,
        'name': fields.String,
        'color': fields.String
    }

    onecat_fields = {
        'msg': fields.String(default='ok'),
        'status': fields.Integer(default=200),
        'data': fields.Nested(catmodel_fields)  # 嵌套
    }

    class OneCatResource(Resource):
        @marshal_with(onecat_fields)
        def get(self):
            cat = Cat.query.first()
            data = {
                # msg 使用默認值尖坤,可以省略不寫
                # status 使用默認只稳懒,也可以不寫
                'data': cat
            }
            return data

# 示例2
    """ 獲取所有貓的數(shù)據(jù)結(jié)構(gòu)
        {
            'msg':'ok',
            'status': 200,
            'data': [
                {
                    'id': 1,
                    'name': 'TOM1',
                    'color': '紅色'
                },
                {
                    'id': 2,
                    'name': 'TOM2',
                    'color': '紅色'
                },
                {
                    'id': 3,
                    'name': 'TOM3',
                    'color': '紅色'
                },
                ...

            ]
        }
    """
    catmodel_fields = {
        'id': fields.Integer,
        'name': fields.String,
        'color': fields.String
    }

    cats_fields = {
        'msg': fields.String(default='ok'),
        'status': fields.Integer(default=200),
        'data': fields.List(fields.Nested(catmodel_fields))
    }

    class CatResource(Resource):
        @marshal_with(cats_fields)
        def get(self):
            cats = Cat.query.all()
            data = {
                'msg': 'ok!',
                'status': 200,
                'data': cats
            }
            return data

  • 請求參數(shù)解析
- 基本使用
    # https://127.0.0.1/showview/?page=1
    parser = reqparse.RequestParser()
    # 接受參數(shù)page,類型是str,錯誤提示help
    parser.add_argument('page', type=str, help='請輸入頁碼')

    class ShowView(Resource):
        def get(self):
            parser = parser.parse_args()
            c_page = parser.get('page') or 1

        def post(self):
            parser = parser.parse_args()
            c_page = parser.get('page') or 1

- 必須參數(shù) required=True
    # 該參數(shù)必須傳入
    parser.add_argument('page', type=int, help='請輸入頁碼', required=True)

- 多參數(shù)(列表)
    # 如果要接受一個鍵有多個值的話,可以傳入 action='append'
    # https://127.0.0.1/showview/?name='liming'&page=1&name='zhangsan'
    parser.add_argument('name', type=str, action='append')

- 參數(shù)位置
    參數(shù)位置: form慢味、args场梆、headers、cookies纯路、files(上傳文件)

作者:西門奄
鏈接:http://www.reibang.com/u/77035eb804c3
來源:簡書
簡書著作權(quán)歸作者所有或油,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末驰唬,一起剝皮案震驚了整個濱河市顶岸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌叫编,老刑警劉巖蜕琴,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異宵溅,居然都是意外死亡凌简,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門恃逻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雏搂,“玉大人藕施,你說我怎么就攤上這事⊥怪#” “怎么了裳食?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芙沥。 經(jīng)常有香客問我诲祸,道長,這世上最難降的妖魔是什么而昨? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任救氯,我火速辦了婚禮,結(jié)果婚禮上歌憨,老公的妹妹穿的比我還像新娘着憨。我一直安慰自己,他們只是感情好务嫡,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布甲抖。 她就那樣靜靜地躺著,像睡著了一般心铃。 火紅的嫁衣襯著肌膚如雪准谚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天去扣,我揣著相機與錄音氛魁,去河邊找鬼。 笑死厅篓,一個胖子當(dāng)著我的面吹牛秀存,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播羽氮,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼或链,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了档押?” 一聲冷哼從身側(cè)響起澳盐,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎令宿,沒想到半個月后叼耙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡粒没,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年筛婉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片癞松。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡爽撒,死狀恐怖入蛆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情硕勿,我是刑警寧澤哨毁,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站源武,受9級特大地震影響扼褪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜粱栖,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一话浇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧查排,春花似錦凳枝、人聲如沸抄沮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叛买。三九已至砂代,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間率挣,已是汗流浹背刻伊。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留椒功,地道東北人捶箱。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像动漾,于是被迫代替她去往敵國和親丁屎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一旱眯、REST 問題 網(wǎng)絡(luò)應(yīng)用程序晨川,分為前端和后端兩個部分。當(dāng)前的發(fā)展趨勢删豺,就是前端設(shè)備層出不窮(手機共虑、平板、桌面電...
    EndEvent閱讀 2,258評論 0 4
  • Flask之REST&API設(shè)計 一呀页、REST(一種軟件架構(gòu)風(fēng)格) 一)妈拌、問題 網(wǎng)絡(luò)應(yīng)用程序,分為前端和后端兩個部...
    月亮是我踢彎得閱讀 2,197評論 0 2
  • 筆記 RESTful架構(gòu)風(fēng)格概述 RESTful架構(gòu)風(fēng)格 RESTful架構(gòu)風(fēng)格最初由Roy T. Fieldin...
    plutoese閱讀 12,630評論 3 58
  • 輕舟.賽文/秋明輕舟一葉滑過鏡面漣漪搖曳面露微紅回眸乜彩蝶飛舞桃紅柳綠
    遺落在麥田里的詩閱讀 142評論 0 0