更多的有关FLASK API的事
书接上文hello Flask:
- 如何安装flask
- 如何用flask书写一个API接口
- 如何处理request,并response
- 如何用POSTMAN和JS发出request
现在我们需要更加规范的处理方法,从创建一个python项目开始!
养成书写python项目的良好习惯
'''
创建虚拟环境以隔离开发环境
'''
#install virtualenv
> pip3 install virtualenv
#在当前目录创建虚拟环境,by python3
> virtualenv ll_env --python = python3
#ll_env是环境名,linux一般习惯取名.env,这样就是隐藏文件了, --python=python3是为了有多个python环境准备的,还有一些其他的知识,自行查询资料
#linux进入虚拟环境
> source .env/bin/activate
#window进入虚拟环境
> .\ll_env\Scripts\activate
#退出
> deactivate
注意:以上创建的是空的环境,需要重新下flask包
参考
插件介绍Flask-RESTful
安装
> pip3 install Flask-RESTful
最好的参考
官方文档
我们来测试一下
from flask import Flask
from flask_restful import Resource,Api
app = Flask(__name__)
#定义一个程序的入口点,你可能需要用一个Flask应用初始化它
api = Api(app)
#定义一个抽象的RESTful资源,它继承自Resource
class Student(Resource):
def get(self,name):
return {'Student':name}
api.add_resource(Student,'/student/<string:name>')
app.run(port=5000)
接下来用flask_restful重写上一篇文章的逻辑
from flask import Flask,request
from flask_restful import Resource,Api
app = Flask(__name__)
#定义一个程序的入口点,你可能需要用一个Flask应用初始化它
api = Api(app)
items = [
]
#定义一个抽象的RESTful资源,它继承自Resource
class Item(Resource):
def get(self,name):
item = next(filter(lambda x:x['name'] == name,items),None)
return {'item':item},200 if item is not None else 404
def post(self,name):
if next(filter(lambda x:x['name'] == name,items),None) is not None:
return {'Message':'An item with name "{}" already exists.'.format(name)},400
date = request.get_json(force = True)
'''
force = True,不检查header的content-type='application/JSON'
silent – 静默解析错误并返回None
'''
item = {'name':name,'price':date['price']}
items.append(item)
return item,201
class ItemList(Resource):
def get(self):
return items
api.add_resource(Item,'/item/<string:name>')
api.add_resource(ItemList,'/items')
app.run(port=5000,debug=True)
插件介绍Flask-JWT
JWT全名是JSON web Token,是通过Token实现的用户权限认证机制。并编码传输的数据
安装
> pip3 install Flask-JWT
官方参考
官方文档
示例
from flask_jwt import JWT,jwt_required
from security import authenticate,identity
#可以用os.urandom(24)生成随机的密钥
app.secret_key = b"\x8e\xaes\x01\xb7'p\xa81\xb7\x92\xca\xc5\x1a9^\xa3\x18\xb3\rOx<x"
jwt = JWT(app,authenticate,identity)#导入用户认证机制,会创建/auth
我们可以通过JWT这个类自行创建一个'/auth'目录下的认证机制
但是需要我们提供两个方法:authenticate,identity
authenticate:POST用户名和密码,返回用户信息
identity:根据之前校验取得的凭证返回用户
创建文件./security.py和./user.py示例如下(当然正常情况下,第一不存用户密码,第二应该与数据库进行交互,这里只做示例,所以也不多深究)
from werkzeug.security import safe_str_cmp
#这种比较方法可以预防编码不同
from user import User
users = [
User(1,"Bomb","qsc")
]
username_mapping = { u.username:u for u in users }
userid_mapping = { u.id:u for u in users }
def authenticate(username,password):
#通过账密进行用户认证
user = username_mapping.get(username,None)
if user and safe_str_cmp(user.password , password):
return user
def identity(payload):
#根据凭证取得用户
user_id = payload['identity']
ccs = userid_mapping.get(user_id,None)
return userid_mapping.get(user_id,None)
用户信息./user.py,一个非常简单的只有账密和id的类
class User():
def __init__(self,_id,username,password):
self.id = id
self.username = username
self.password = password
可以看到上文伪造了一个实际存在的用户Bomb,我们可以POST下/auth,看下机制。
返回Token
然后更改./app.py,要求某些请求需要Token认证
from flask_jwt import JWT,jwt_required
class Item(Resource):
@jwt_required()
def get(self,name):
item = next(filter(lambda x:x['name'] == name,items),None)
return {'item':item},200 if item is not None else 404
这里我们引入了装饰器jwt_required,关于装饰器可以阅读下文的连接
此时我们再请求GET /item/<name>,我们得到的回覆如下:
401错误
复制之前的TOKEN,我们来进行验证
当我们拥有令牌时
去使用DEL和PUT
这里提前说一下:HTTP动作是人为定义的,但开发时请尽力符合规范。
@jwt_required()
def delete(self,name):
global items
items = list(filter(lambda x : x['name'] != name,items))
return {'message': 'Item deleted'}
@jwt_required()
def put(self, name):
date = request.get_json()
#Item.parser.parse_args
#data = Item.parser.parse_args()
# Once again, print something not in the args to verify everything works
item = next(filter(lambda x: x['name'] == name, items), None)
if item is None:
item = {'name': name, 'price': data['price']}
items.append(item)
else:
item.update(data)
return item
这里注释部分引入了新机制from flask_restful import reqparse,我们可以通过这个包约束请求的规范,俗称request parsing。
#定义约束
parser = reqparse.RequestParser()
parser.add_argument('price',
#转化为float类型
type=float,
#必填
required=True,
#异常返回值
help="This field cannot be left blank!"
)
通过这个我们来改写下PUT方法
#@jwt_required()
def put(self, name):
data = Item.parser.parse_args()
print(data)
# Once again, print something not in the args to verify everything works
item = next(filter(lambda x: x['name'] == name, items), None)
if item is None:
item = {'name': name, 'price': data['price']}
items.append(item)
else:
item.update(data)
return item
这种方法好处在于不需要我们去校验request的规范,并且只会筛选已经定义的规范
总结,我们学到了:
如何规范的创建一个Python项目
如何规范的创建一个Resource对象
如何加入TOKEN验证
如何规范处理REQUEST请求
下一章
flask与DB交互