美文网首页
更多的有关FLASK API的事

更多的有关FLASK API的事

作者: 浪尖的游鱼 | 来源:发表于2019-06-24 13:29 被阅读0次

    书接上文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交互

    回到目录

    相关文章

      网友评论

          本文标题:更多的有关FLASK API的事

          本文链接:https://www.haomeiwen.com/subject/rndyqctx.html