用Flask建立RESTful API

比過黑客松或是數據探勘一定多少接觸過api,可是呼叫api一行指令的背後又是怎麼做的呢?

上網找了幾筆文章發現原來有個很簡單的方式可以建立自己的api,那就是使用flask框架。flask架構簡單運行速度比Django快,且同樣也是使用簡單易懂的Python語言(撒花),通常適合用來做static 網頁的後段。而這裡我就以flask為框架弄出一個能parse 出json 資料的api

安裝:

在unix上,開啟terminal  安裝virtualenv

sudo pip install virtualenv

成立一個flask folder, 在folder內創建一個隔絕的Python 環境。

virtualenv  myvenv

啟動Python環境(退出則是: deactivate)

source myvenv/bin/activate

安裝flask : pip install Flask

之後成立一個app.py檔案,裡面寫著:

from flask import Flask, jsonify
app = Flask(__name__)

data = [
     {
         'id':1233,
         'name':u'Jason',
         'description':u'handsome but impatient'
     },
     {
          'id':1234,
          'name':u'Peter',
          'description':u'tall and humorous'
      }
]

@app.route("/example/api/v0.1/name",methods = ['GET'])
def get_data():
    return jsonify({'data':data})

if __name__ == "__main__":
    app.run(debug = True)

其中data是你的數據List,。當有人GET時,flask就會將data轉為json格式並回傳給他內所data內容。

執行:  python app.py

在另一個terminal視窗執行: curl -i http://localhost:5000/example/api/v0.1/data

輸出結果如下(結果在右邊):

旁邊的terminal

如果想要parse單筆資料要怎麼辦呢?

from flask import Flask, jsonify
app = Flask(__name__)

data = [
     {
         'id':1233,
         'name':u'Jason',
         'description':u'handsome but impatient'
     },
     {
          'id':1234,
          'name':u'Peter',
          'description':u'tall and humorous'
      }
 ] 

@app.route("/example/api/v0.1/name/<int:data_id>",methods = ['GET']) 
def get_data(data_id):
     people = [people for people in data if people['id'] == data_id ]
     if len(people) == 0:
          abort(404) 
     return jsonify({'data':people[0]}) 

@app.errorhandler(404)
def not_found(error):
     return make_response(jsonify({'error':'Not Found'}),404)

if __name__ == "__main__": 
     app.run(debug = True)

在另一個terminal視窗執行:  curl -i http://localhost:5000/example/api/v0.1/name/1233

輸出結果如下(結果在右邊):

api2

當然API侷限在parse資料也太無聊了,所以要能添加與刪除資料吧

from flask import Flask, jsonify, make_response, abort
app = Flask(__name__)

data = [
     {
         'id':1233,
         'name':u'Jason',
         'description':u'handsome but impatient'
     },
     {
          'id':1234,
          'name':u'Peter',
          'description':u'tall and humorous'
      },
      {
          'id':1235,
          'name':u'Henricks',
          'description':u'Geek'
      }
 ] 

@app.route("/example/api/v0.1/name/<int:data_id>",methods = ['GET']) 
def get_data(data_id):
     people = [people for people in data if people['id'] == data_id ]
     if len(people) == 0:
          abort(404) 
     return jsonify({'data':people[0]}) 

@app.errorhandler(404)
def not_found(error):
     return make_response(jsonify({'error':'Not Found'}),404)

#delete database data
@app.route("/example/api/v0.1/name/<int:data_id>",methods = ['DELETE']) 
def delete_task(data_id):
    people = [people for people in data if people['id'] == data_id]
    if len(people) == 0:
          abort(404)
    data.remove(people[0])
    return jsonify({'result' : True})

if __name__ == "__main__": 
     app.run(debug = True)

 

在另一個terminal視窗執行:curl -i -H “Content-Type: application/json” -X DELETE -d ‘{“name”:”Jason”}’ http://localhost:5000/example/api/v0.1/name/1233

 

api_delete3

再次呼叫id 1233的話,就回傳沒有這筆資料了

api_delet4

 

POST資料

好了我們能刪除資料了,刪錯了怎麼辦??

用POST指令把它添加回去好了

from flask import Flask, jsonify
app = Flask(__name__)

data = [
     {
         'id':1233,
         'name':u'Jason',
         'description':u'handsome but impatient'
     },
     {
          'id':1234,
          'name':u'Peter',
          'description':u'tall and humorous'
      }
 ] 

@app.route("/example/api/v0.1/name/<int:data_id>",methods = ['GET']) 
def get_data(data_id):
     people = [people for people in data if people['id'] == data_id ]
     if len(people) == 0:
          abort(404) 
     return jsonify({'data':people[0]}) 

@app.route("/example/api/v0.1/name",methods = ['POST'])
def create_task():
     if not request.json or not 'name' in request.json:
          abort(400)
     people = {
          'id': data[-1]['id'] + 1, #id is default as the next id num
          'name': request.json['name'], #name is a must
          'description': request.json.get('description', ""),
     }
     data.append(people)
     return jsonify({'data': data}), 201 #return all data
@app.errorhandler(404)
def not_found(error):
     return make_response(jsonify({'error':'Not Found'}),404)

if __name__ == "__main__": 
     app.run(debug = True)

以上的api要求添加新的個人資料時,必須要有該資料的名字,如果沒有則回傳400錯誤。

執行一下指令就能添加一個名為DBlackKat的個人資料:

curl -i -H “Content-Type: application/json” -X POST -d ‘{“name”:”DBlackKat”}’ http://localhost:5000/example/api/v0.1/name

api_post2
function最後要求回傳所有資料

學會了怎麼添加那麼如何更改個人資料呢?

from flask import Flask, jsonify, make_response, abort, request
app = Flask(__name__)

data = [
     {
         'id':1233,
         'name':u'Jason',
         'description':u'handsome but impatient'
     },
     {
          'id':1234,
          'name':u'Peter',
          'description':u'tall and humorous'
      }
 ] 

@app.route('/todo/api/v1.0/tasks/<int:data_id>', methods=['PUT'])
def update_task(data_id):
    people = [people for people in data if people['id'] == data_id]
    if len(people) == 0:
        abort(404)
    if not request.json:
        abort(400)
    if 'name' in request.json and type(request.json['name']) != unicode:
        abort(400)
    if 'description' in request.json and type(request.json['description']) is not unicode:
        abort(400)
    people[0]['name'] = request.json.get('name', people[0]['name'])
    people[0]['description'] = request.json.get('description', people[0]['description'])
    return jsonify({'result': people[0]})

if __name__ == "__main__": 
    app.run(debug = True)

在另一個終端執行:

curl -i -H “Content-Type: application/json” -X PUT -d ‘{“name”:”Raymond”}’ http://localhost:5000/example/api/v0.1/name/1233

 

api_put2

輸出結果如上,注意 Json 名字已經被更改成Raymond了

以上都是建立一個開放式的api, 如果今天想要使用認證才能登錄要怎麼辦呢?

Python 對於一切問題都有自己的library這裡我們就安裝 http_auth,

在同一個虛擬環境下執行 pip install http_auth

一下簡單介紹最基本的認證方式,如果是使用在產品上建議使用http_auth的flask網站上提到的範例,並且secret_key是由file讀取為佳。

from flask import Flask, jsonify, abort, make_response, request
from flask_httpauth import HTTPBasicAuth

app = Flask(__name__)

auth = HTTPBasicAuth()

data = [
       {
          'id':1233,
          'name':u'Jason',
          'description':u'handsome but impatient'
       },
       {
          'id':1234,
          'name':u'Peter',
          'description':u'tall and humorous'
       }
]

@auth.get_password
def get_password(username):
    if username == 'theblackcat102':
         return 'blablabla' #this is our password
    return None

@auth.error_handler
def unauthorized(): #make unauthorised access return
    return make_response(jsonify({'error': 'Unauthorised access'}), 403)

@app.route("/example/api/v0.1/name/<int:data_id>",methods = ['GET']) 
@auth.login_required
def get_data(data_id):
    people = [people for people in data if people['id'] == data_id ]
    if len(people) == 0:
        abort(404) 
    return jsonify({'data':people[0]}) 

@app.errorhandler(404)
@auth.login_required
def not_found(error):
     return make_response(jsonify({'error':'Not Found'}),404)

#delete database data
@app.route("/example/api/v0.1/name/<int:data_id>",methods = ['DELETE'])
@auth.login_required 
def delete_task(data_id):
     people = [people for people in data if people['id'] == data_id]
     if len(people) == 0:
          abort(404)
     data.remove(people[0])
     return jsonify({'result' : True})

if __name__ == "__main__": 
     app.run(debug = True)

在另一個終端執行:

curl -u theblackcat102:blablabla -i http://localhost:5000/example/api/v0.1/name/1233

輸出結果如下:

unauthorized_access3

如果密碼打錯了,結果就會出現我們設定的回饋(注意密碼打錯了):

unauthorized_access4

參考來源: http://blog.miguelgrinberg.com/post/designing-a-restful-api-with-python-and-flask

 

Advertisements

Silicon Valley :追劇完三季後感?

silicon valley Intro

我關於矽谷的認知,很多都來自對於早期閱讀steve jobs, 看social network ( 故事靈感來自fb 的創辦故事 ), 閱讀新聞雜誌得來的。

期末結束前夕,youtube上跳出了silicon valley的搞笑短片,按耐不住之下就點進去看了一下。於是我就在隔天三天內把第一第二季看完了,第三季也在今天順利看完( 1 Mbps 網速沒有讓我更失望 )。

Silicon Valley, 這部戲講了一個典型的新創公司在矽谷的各種日常故事。例如:面臨VC募資時的各種談判搞笑、尋找管理與領導諮詢(別小看這個環節)、迅速壯大所面臨的問題等等,都一一在這裡出現了。

故事中的5位演員( 分別扮演公司的: CEO/founder , PR , CTO , full stack / backend engineer , software engineer ) 精湛的演出為這部連續劇增添了許多幽默環節,從頭到尾留住了觀眾的注意力。

silicon-valley
故事的男主角們(左到右):兩位工程師,CEO,CTO?,PR

最近看了許多關於世界上不會出現第二個矽谷的各種評論文章後,對這部戲的寫實感大感讚嘆。待在新竹,台灣已有差不多一年時間,當地政府一直推行各種技術創新、專利轉讓等等的口號,極力將這裡打造成為新創公司萌芽的地方。然而,正如許多評論文章中提到的,美國矽谷不可能會在台灣發生是因為矽谷的文化正是由風險投資人、技術人才、開放自由的環境匯集一處才孕育出的獨有文化。而台灣正是少了這些敢於投資與冒險的VC、天使投資人與尋求資深領導人的諮詢管道。台灣新創公司據我了解不是籌集不到資金死在沙灘上,就是在海洋中處於半死不活的狀態(不知道TapPay的近況如何了?)

返回正題,Silicon Valley 以幽默的方式,道出了矽谷文化鮮少人知的另一面。但是也許集數太少,很多時候故事即將到了高潮時,那一季就結束了。每段男主角們遇到的挑戰之間銜接性很好,做到了前呼後應的效果。對於在矽谷裡的各個角色(工程師、投資人、億萬富翁、資深領導人)的性格特點勾勒出非常到味。十分推薦週末在家消磨時間,或者半夜寫程式沒動力了可以看一看。