flask开发restful api

Posted Leo_wlCnBlogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flask开发restful api相关的知识,希望对你有一定的参考价值。

flask开发restful api

如果有几个原因可以让你爱上flask这个极其灵活的库,我想蓝图绝对应该算上一个,部署蓝图以后,你会发现整个程序结构非常清晰,模块之间相互不影响。蓝图对restful api的最明显效果就是版本控制;而对整个项目来说,总要有后台管理系统吧,总要有web管理吧,但这些东西不能全部放到view.py。不单单是这样,如果你是一个经验丰富的程序员,你应该知道,一个程序最好只有一个入口点,从这个入口点进去,全是单向的,就像一棵树一样,入口点就在树根,然后蔓延到树干,树枝。树枝和树枝之间最好不要太多交集,也就是我们通常所说的 低耦合。

  好了,说了这么多,我们举个简单例子看看。假设你的一款app已经上架,现在公司要开发新的版本,新版本不但要增加新的接口,可能还要修改以前老的接口。但如果修改老的接口,那老版本的用户又不能正常访问了,要是用户更新不及时,是不是这些接口就不能访问了?如果我需要这个接口可以维持一阵子,过一段时间后,再停用,该如何实现呢?

  下面这个截图是我原先的项目结构。

  

  如果要增加接口和修改接口,只能在view.py里面做,我这个只是举例,在真实的项目中,一个中等app,最少有上百个接口,如何快速找到接口,定位问题,是一门很好的学问。

  首先,先在app下增加一个文件夹,api_1_0作为版本1.0存放地方,是我们的一个树枝,把之前的view.py迁移到里面去。结构如下:

  

  我们之前总是在view.py里面运行app,这个肯定不行,不能把入口点放在某一个树枝吧。要把整个app拉出来,在上一级来启动项目,那么就再增加一个run.py文件,专门来运行整个项目,整个run.py代码如下

复制代码
# coding:utf-8
from flask import Flask
from config import Conf
import redis
from qiniu import Auth, put_file, etag, urlsafe_base64_encode


def create_app():
    app = Flask(__name__)
    app.config.from_object(Conf)
    app.secret_key = app.config[\'SECRET_KEY\']
    app.redis = redis.Redis(host=app.config[\'REDIS_HOST\'], port=app.config[\'REDIS_PORT\'],
                            db=app.config[\'REDIS_DB\'], password=app.config[\'REDIS_PASSWORD\'])

    app.q = Auth(access_key=app.config[\'QINIU_ACCESS_KEY\'], secret_key=app.config[\'QINIU_SECRET_KEY\'])
    app.bucket_name = app.config[\'BUCKET_NAME\']
    app.debug = app.config[\'DEBUG\']
    return app

if __name__ == \'__main__\':
    app = create_app()
    app.run(debug=app.debug, host=\'0.0.0.0\', port=5001)
复制代码

这边就是整个项目的总起点,是整个树的根(其实这边还可以再把run.py放在外面,这边接下来会继续讲)。

恩,看起来好了,但我们还是没有看到蓝图。好了,这边就说到了,之前view.py里面全部用的app.route,之前没问题,因为它本身就是根,可是你现在已经不是根了,那就要变换一下,在api_1_0/__init__.py里,添加如下代码:

复制代码
# coding:utf-8
from flask import Blueprint

api = Blueprint(\'api\', __name__)

from . import view
复制代码

这边解释一下,首先定义一个蓝图,这个不用讲了,你用之前,肯定要定义一下吧,蓝图名字就叫api。下面一行代码有点意思,from . import view, 这个代码,我发现用蓝图的人,很多都忘写了。如果你是一个python老手,你应该知道,导入python文件,其实就是运行导入的那个文件。在这边,你导入一次,就是就是告诉上级,这边还有个view.py文件,里面覆盖了一些接口。整个根就知道,哦,如果有接口访问这,我就指向你这边。好好理解上面的粗体字。

好了,树枝这边已经定义了,那树根那边也应该重新写一下。一个request到树根那,树根根据url来指向树枝,树根怎么指向呢?代码如下:

复制代码
def create_app():
    app = Flask(__name__)
    app.config.from_object(Conf)
    app.secret_key = app.config[\'SECRET_KEY\']
    app.redis = redis.Redis(host=app.config[\'REDIS_HOST\'], port=app.config[\'REDIS_PORT\'],
                            db=app.config[\'REDIS_DB\'], password=app.config[\'REDIS_PASSWORD\'])

    app.q = Auth(access_key=app.config[\'QINIU_ACCESS_KEY\'], secret_key=app.config[\'QINIU_SECRET_KEY\'])
    app.bucket_name = app.config[\'BUCKET_NAME\']
    app.debug = app.config[\'DEBUG\']
    
    from .app_1_0 import api as api_1_0_blueprint
    app.register_blueprint(api_1_0_blueprint, url_prefix=\'/api/v1000\')
    
    return app
复制代码

看到增加的2行代码没有,这个就是树根指向树枝的代码。

好了,我们现在整个流程应该清楚了,请求从树根进来,树根根据蓝图指向某一个树枝,这个树枝具体处理请求,返回。

那自然,最后一段树枝具体处理,也要改变咯。

原先view.py代码改变一下,如下:

复制代码
# coding:utf-8
from flask import Flask, request, jsonify, g, render_template, redirect, url_for, session, current_app
from app.model import User, db_session, MaintainRecord
import hashlib
import time
import uuid
from app.util import message_validate
import random
from functools import wraps

from . import api


def login_check(f):
    @wraps(f)
    def decorator(*args, **kwargs):
        token = request.headers.get(\'token\')
        if not token:
            return jsonify({\'code\': 0, \'message\': \'需要验证\'})
        
        phone_number = current_app.redis.get(\'token:%s\' % token)
        if not phone_number or token != current_app.redis.hget(\'user:%s\' % phone_number, \'token\'):
            return jsonify({\'code\': 2, \'message\': \'验证信息错误\'})

        return f(*args, **kwargs)
    return decorator


@api.before_request
def before_request():
    token = request.headers.get(\'token\')
    phone_number = current_app.redis.get(\'token:%s\' % token)
    if phone_number:
        g.current_user = User.query.filter_by(phone_number=phone_number).first()
        g.token = token
    return


@api.route(\'/login\', methods=[\'POST\'])
def login():
    phone_number = request.get_json().get(\'phone_number\')
    password = request.get_json().get(\'password\')
    user = User.query.filter_by(phone_number=phone_number).first()
    if not user:
        return jsonify({\'code\': 0, \'message\': \'没有此用户\'})

    if user.password != password:
        return jsonify({\'code\': 0, \'message\': \'密码错误\'})

    m = hashlib.md5()
    m.update(phone_number)
    m.update(password)
    m.update(str(int(time.time())))
    token = m.hexdigest()

    pipeline = current_app.redis.pipeline()
    pipeline.hmset(\'user:%s\' % user.phone_number, {\'token\': token, \'nickname\': user.nickname, \'app_online\': 1})
    pipeline.set(\'token:%s\' % token, user.phone_number)
    pipeline.expire(\'token:%s\' % token, 3600*24*30)
    pipeline.execute()

    return jsonify({\'code\': 1, \'message\': \'成功登录\', \'nickname\': user.nickname, \'token\': token})


@api.route(\'/user\')
@login_check
def user():
    user = g.current_user

    nickname = current_app.redis.hget(\'user:%s\' % user.phone_number, \'nickname\')
    return jsonify({\'code\': 1, \'nickname\': nickname, \'phone_number\': user.phone_number})


@api.route(\'/logout\')
@login_check
def logout():
    user = g.current_user

    pipeline = current_app.redis.pipeline()
    pipeline.delete(\'token:%s\' % g.token)
    pipeline.hmset(\'user:%s\' % user.phone_number, {\'app_online\': 0})
    pipeline.execute()
    return jsonify({\'code\': 1, \'message\': \'成功注销\'})


@api.route(\'/get-qiniu-token\')
def get_qiniu_token():
    key = uuid.uuid4()
    token = current_app.q.upload_token(current_app.bucket_name, key, 3600)
    return jsonify({\'code\': 1, \'key\': key, \'token\': token})


@api.route(\'/set-head-picture\', methods=[\'POST\'])
@login_check
def set_head_picture():
    head_picture = request.get_json().get(\'head_picture\')
    user = g.current_user
    user.head_picture = head_picture
    try:
        db_session.commit()
    except Exception as e:
        print e
        db_session.rollback()
        return jsonify({\'code\': 0, \'message\': \'未能成功上传\'})
    current_app.redis.hset(\'user:%s\' % user.phone_number, \'head_picture\', head_picture)
    return jsonify({\'code\': 1, \'message\': \'成功上传\'})


@api.route(\'/register-step-1\', methods=[\'POST\'])
def register_step_1():
    """
    接受phone_number,发送短信
    """
    phone_number = request.get_json().get(\'phone_number\')
    user = User.query.filter_by(phone_number=phone_number).first()

    if user:
        return jsonify({\'code\': 0, \'message\': \'该用户已经存在,注册失败\'})
    validate_number = str(random.randint(100000, 1000000))
    result, err_message = message_validate(phone_number, validate_number)

    if not result:
        return jsonify({\'code\': 0, \'message\': err_message})

    pipeline = current_app.redis.pipeline()
    pipeline.set(\'validate:%s\' % phone_number, validate_number)
    pipeline.expire(\'validate:%s\' % phone_number, 60)
    pipeline.execute()

    return jsonify({\'code\': 1, \'message\': \'发送成功\'})


@api.route(\'/register-step-2\', methods=[\'POST\'])
def register_step_2():
    """
    验证短信接口
    """
    phone_number = request.get_json().get(\'phone_number\')
    validate_number = request.get_json().get(\'validate_number\')
    validate_number_in_redis = current_app.redis.get(\'validate:%s\' % phone_number)

    if validate_number != validate_number_in_redis:
        return jsonify({\'code\': 0, \'message\': \'验证没有通过\'})

    pipe_line = current_app.redis.pipeline()
    pipe_line.set(\'is_validate:%s\' % phone_number, \'1\')
    pipe_line.expire(\'is_validate:%s\' % phone_number, 120)
    pipe_line.execute()

    return jsonify({\'code\': 1, \'message\': \'短信验证通过\'})


@api.route(\'/register-step-3\', methods=[\'POST\'])
def register_step_3():
    """
    密码提交
    """
    phone_number = request.get_json().get(\'phone_number\')
    password = request.get_json().get(\'password\')
    password_confirm = request.get_json().get(\'password_confirm\')

    if len(password) < 7 or len(password) > 30:
        # 这边可以自己拓展条件
        return jsonify({\'code\': 0, \'message\': \'密码长度不符合要求\'})

    if password != password_confirm:
        return jsonify({\'code\': 0, \'message\': \'密码和密码确认不一致\'})

    is_validate = current_app.redis.get(\'is_validate:%s\' % phone_number)

    if is_validate != \'1\':
        return jsonify({\'code\': 0, \'message\': \'验证码没有通过\'})

    pipeline = current_app.redis.pipeline()
    pipeline.hset(\'register:%s\' % phone_number, \'password\', password)
    pipeline.expire(\'register:%s\' % phone_number, 120)
    pipeline.execute()

    return jsonify({\'code\': 1, \'message\': \'提交密码成功\'})


@api.route(\'/register-step-4\', methods=[\'POST\'])
def register_step_4():
    """
    基本资料提交
    """
    phone_number = request.get_json().get(\'phone_number\')
    nickname = request.get_json().get(\'nickname\')

    is_validate = current_app.redis.get(\'is_validate:%s\' % phone_number)

    if is_validate != \'1\':
        return jsonify({\'code\': 0, \'message\': \'验证码没有通过\'})

    password = current_app.redis.hget(\'register:%s\' % phone_number, \'password\')

    new_user = User(phone_number=phone_number, password=password, nickname=nickname)
    db_session.add(new_user)

    try:
        db_session.commit()
    except Exception as e:
        print e
        db_session.rollback()
        return jsonify({\'code\': 0, \'message\': \'注册失败\'})
    finally:
        current_app.redis.delete(\'is_validate:%s\' % phone_number)
        current_app.redis.delete(\'register:%s\' % phone_number)

    return jsonify({\'code\': 1, \'message\': \'注册成功\'})


@api.teardown_request
def handle_teardown_request(exception):
    db_session.remove()
复制代码

  这边有好几个需要注意的点。

  第一,运行的代码取消掉了,因为统一从run.py来运行,作为入口点。

  第二,原先的app.route也全部改成api.route, api也从本地的__init__.py中导入。因为你现在代表树枝,不能代表整棵树了。

  第三,app.redis,可以用current_app.redis来代替,其实就是我在run.py中定义的一些变量,在整颗树中使用。

  

好了,我们运行一下python run.py试试看吧。这边需要注意的是,url也不一样了哦,client.py中,要用不同的url了。client.py运行代码如下:

复制代码
if __name__ == \'__main__\':
    api = APITest(\'http://127.0.0.1:5001/api/v1000\')
    u = api.login(\'13565208554\', \'123456\')
    print u
    u1 = api.user()
    print u1
    api.logout()
复制代码

python run.py返回的url,看看详细情况。

  

 

  整个运行情况问题,那么回到最上面提到的问题。老板看我们第一个版本做的非常稳定,要开发第二个版本,先不管新增的功能,老板觉得你上一个版本的login接口写的不好,直接明文把用户名和密码传输过去了,安全问题得不到保障。现在要求是login接口重写,其他不变,并且上个版本的接口暂时还不能停止。

  如果按照我们以前的想法,再增加一个不同的接口呗。嗯!方法不错,要是要修改20个接口呢?重写吗?怎么分得清哪个对应哪个版本?就算这次分清了,再更新5个版本,你还知道原来写的什么吗?

  好了,上面一堆废话就是为了衬托项目结构的重要性的。版本1.1,我们重新写一个树枝,这个树枝跟1.0的树枝没有任何交集。有了1.0,1.1就非常好写了。

  把整个api_1_0直接复制到api_1_1中。没错,你没看错,就是整个复制过去。

  然后把api_1_1中的__init__.py修改一下,代码如下:

复制代码
# coding:utf-8
from flask import Blueprint

api = Blueprint(\'api1_1\', __name__)

from . import view
复制代码

  其实就是把蓝图名字修改了一下。整个项目结构如下图:

  在run.py中,增加如下代码。

复制代码
def create_app():
    app = Flask(__name__)
    app.config.from_object(Conf)
    app.secret_key = app.config[\'SECRET_KEY\']
    app.redis = redis.Redis(host=app.config[\'REDIS_HOST\'], port=app.config[\'REDIS_PORT\'],
                            db=app.config[\'REDIS_DB\'], password=app.config[\'REDIS_PASSWORD\'])

    app.q = Auth(access_key=app.config[\'QINIU_ACCESS_KEY\'], secret_key=app.config[\'QINIU_SECRET_KEY\'])
    app.bucket_name = app.config[\'BUCKET_NAME\']
    app.debug = app.config[\'DEBUG\']

    from app_1_0 import api as api_1_0_blueprint
    app.register_blueprint(api_1_0_blueprint, url_prefix=\'/api/v1000\')
    
    from api_1_1 import api as api_1_1_blueprint
    app.register_blueprint(api_1_1_blueprint, url_prefix=\'/api/v1100\')

    return app
复制代码

好了,整个复制过程完工,看看实际情况吧。

我们先不修改登录接口,就看一下效果。client.py运行代码

复制代码
if __name__ == \'__main__\':
    api = APITest(\'http://127.0.0.1:5001/api/v1000\')
    u = api.login(\'13565208554\', \'123456\')
    print u
    u1 = api.user()
    print u1
    api.logout()

    api = APITest(\'http://127.0.0.1:5001/api/v1100\')
    u = api.login(\'13565208554\', \'123456\')
    print u
    u1 = api.user()
    print u1
    api.logout()
复制代码

看看ide调试结果吧。

 

 是不是2个版本同时支持了?结构是不是非常非常清晰?

  结构调整到这,那就听老板的意思,开始写新的接口吧。老板说,上次登录接口不安全,要修改一下。一般来说,验证时,都是把用户名,和 密码+随机值+时间戳 的加密方式传过去,我们也萧规曹随吧,新版本的login接口代码如下: 

复制代码
@api.route(\'/login\', methods=[\'POST\'])
def login():
    phone_number = request.get_json().get(\'phone_number\')
    encryption_str = request.get_json().get(\'encryption_str\')
    random_str = request.get_json().get(\'random_str\')
    time_stamp = request.get_json().get(\'time_stamp\')
    user = User.query.filter_by(phone_number=phone_number).first()

    if not user:
        return jsonify({\'code\': 0, \'message\': \'没有此用户\'})

    password_in_sql = user.password

    s = hashlib.sha256()
    s.update(password_in_sql)
    s.update(random_str)
    s.update(time_stamp)
    server_encryption_str = s.hexdigest()

    if server_encryption_str != encryption_str:
        return jsonify({\'code\': 0, \'message\': \'密码错误\'})

    m = hashlib.md5()
    m.update(phone_number)
    m.update(user.password)
    m.update(str(int(time.time())))
    token = m.hexdigest()

    pipeline = current_app.redis.pipeline()
    pipeline.hmset(\'user:%s\' % user.phone_number, {\'token\': token, \'nickname\': user.nickname, \'app_online\': 1})
    pipeline.set(\'token:%s\' % token, user.phone_number)
    pipeline.expire(\'token:%s\' % token, 3600*24*30)
    pipeline.execute()

    return jsonify({\'code\': 1, \'message\': \'成功登录\', \'nickname\': user.nickname, \'token\': token})
复制代码

代码稍微解释一下,encryption_str就是加密串,是由密码+随机值+时间戳用sha256加密的。传到服务器,服务器也这样加密一下,然后看看2者是不是一致。传输过程不涉及密码传输。就这么简单。

客户端就不能用之前的代码了,需要重写一下。代码如下:

复制代码
# coding:utf-8
import requests
import json
from qiniu import put_file
import time
import random
import hashlib


class API_1_0(object):
    base_url = \'http://127.0.0.1:5001/api/v1000\'

    def __init__(self):
        self.headers = {}
        self.token = None
        self.qiniu_token = None
        self.qiniu_key = None
        self.qiniu_base_url = \'http://7xk6rc.com1.z0.glb.clouddn.com/\'

    def login(self, phone_number, password, path=\'/login\'):
        payload = {\'phone_number\': phone_number, \'password\': password}
        self.headers = {\'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        self.token = response_data.get(\'token\')
        return response_data

    def user(self, path=\'/user\'):
        self.headers = {\'token\': self.token}
        response = requests.get(url=self.base_url + path, headers=self.headers)
        response_data = json.loads(response.content)
        return response_data

    def logout(self, path=\'/logout\'):
        self.headers = {\'token\': self.token}
        response = requests.get(url=self.base_url + path, headers=self.headers)
        response_data = json.loads(response.content)
        return response_data

    def get_qiniu_token(self, path=\'/get-qiniu-token\'):
        response = requests.get(url=self.base_url + path)
        response_data = json.loads(response.content)
        self.qiniu_token = response_data.get(\'token\')
        self.qiniu_key = response_data.get(\'key\')
        if self.qiniu_token and self.qiniu_key:
            print \'成功获取qiniu_token和qiniu_key,分别为%s和%s\' % (self.qiniu_token.encode(\'utf-8\'), self.qiniu_key.encode(\'utf-8\'))
            localfile = \'/home/yudahai/PycharmProjects/blog01/app/my-test.png\'
            ret, info = put_file(self.qiniu_token, self.qiniu_key, localfile)
            print info.status_code
            if info.status_code == 200:
                print \'上传成功\'
                self.head_picture = self.qiniu_base_url + self.qiniu_key
                print \'其url为:\' + self.head_picture.encode(\'utf-8\')
            else:
                print \'上传失败\'
        return response_data

    def set_head_picture(self, path=\'/set-head-picture\'):
        payload = {\'head_picture\': self.head_picture}
        self.headers = {\'token\': self.token, \'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        print response_data.get(\'message\')
        return response_data

    def register_step_1(self, phone_number, path=\'/register-step-1\'):
        payload = {\'phone_number\': phone_number}
        self.headers = {\'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        print response_data.get(\'code\')
        return response_data

    def register_step_2(self, phone_number, validate_number, path=\'/register-step-2\'):
        payload = {\'phone_number\': phone_number, \'validate_number\': validate_number}
        self.headers = {\'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        print response_data.get(\'code\')
        return response_data

    def register_step_3(self, phone_number, password, password_confirm, path=\'/register-step-3\'):
        payload = {\'phone_number\': phone_number, \'password\': password, \'password_confirm\': password_confirm}
        self.headers = {\'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        print response_data.get(\'code\')
        return response_data

    def register_step_4(self, phone_number, nickname, path=\'/register-step-4\'):
        payload = {\'phone_number\': phone_number, \'nickname\': nickname}
        self.headers = {\'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        print response_data.get(\'code\')
        return response_data


class API_1_1(object):
    base_url = \'http://127.0.0.1:5001/api/v1100\'

    def __init__(self):
        self.headers = {}
        self.token = None
        self.qiniu_token = None
        self.qiniu_key = None
        self.qiniu_base_url = \'http://7xk6rc.com1.z0.glb.clouddn.com/\'

    def login(self, phone_number, password, path=\'/login\'):
        random_str = str(random.randint(10000, 100000))
        time_stamp = str(int(time.time()))
        s = hashlib.sha256()
        s.update(password)
        s.update(random_str)
        s.update(time_stamp)
        encryption_str = s.hexdigest()

        payload = {\'phone_number\': phone_number, \'encryption_str\': encryption_str, \'random_str\': random_str, \'time_stamp\': time_stamp}
        self.headers = {\'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        self.token = response_data.get(\'token\')
        return response_data

    def user(self, path=\'/user\'):
        self.headers = {\'token\': self.token}
        response = requests.get(url=self.base_url + path, headers=self.headers)
        response_data = json.loads(response.content)
        return response_data

    def logout(self, path=\'/logout\'):
        self.headers = {\'token\': self.token}
        response = requests.get(url=self.base_url + path, headers=self.headers)
        response_data = json.loads(response.content)
        return response_data

    def get_qiniu_token(self, path=\'/get-qiniu-token\'):
        response = requests.get(url=self.base_url + path)
        response_data = json.loads(response.content)
        self.qiniu_token = response_data.get(\'token\')
        self.qiniu_key = response_data.get(\'key\')
        if self.qiniu_token and self.qiniu_key:
            print \'成功获取qiniu_token和qiniu_key,分别为%s和%s\' % (self.qiniu_token.encode(\'utf-8\'), self.qiniu_key.encode(\'utf-8\'))
            localfile = \'/home/yudahai/PycharmProjects/blog01/app/my-test.png\'
            ret, info = put_file(self.qiniu_token, self.qiniu_key, localfile)
            print info.status_code
            if info.status_code == 200:
                print \'上传成功\'
                self.head_picture = self.qiniu_base_url + self.qiniu_key
                print \'其url为:\' + self.head_picture.encode(\'utf-8\')
            else:
                print \'上传失败\'
        return response_data

    def set_head_picture(self, path=\'/set-head-picture\'):
        payload = {\'head_picture\': self.head_picture}
        self.headers = {\'token\': self.token, \'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        print response_data.get(\'message\')
        return response_data

    def register_step_1(self, phone_number, path=\'/register-step-1\'):
        payload = {\'phone_number\': phone_number}
        self.headers = {\'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        print response_data.get(\'code\')
        return response_data

    def register_step_2(self, phone_number, validate_number, path=\'/register-step-2\'):
        payload = {\'phone_number\': phone_number, \'validate_number\': validate_number}
        self.headers = {\'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        print response_data.get(\'code\')
        return response_data

    def register_step_3(self, phone_number, password, password_confirm, path=\'/register-step-3\'):
        payload = {\'phone_number\': phone_number, \'password\': password, \'password_confirm\': password_confirm}
        self.headers = {\'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        print response_data.get(\'code\')
        return response_data

    def register_step_4(self, phone_number, nickname, path=\'/register-step-4\'):
        payload = {\'phone_number\': phone_number, \'nickname\': nickname}
        self.headers = {\'content-type\': \'application/json\'}
        response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
        response_data = json.loads(response.content)
        print response_data.get(\'code\')
        return response_data

if __name__ == \'__main__\':
    api = API_1_0()
    u = api.login(\'13565208554\', \'123456\')
    print u
    u1 = api.user()
    print u1
    api.logout()

    api = API_1_1()
    u = api.login(\'13565208554\', \'123456\')
    print u
    u1 = api.user()
    print u1
    api.logout()
复制代码

就是复制一遍,然后把base_url定义成不同,仅此而已。其实真是的ios, android也这样。当需要更新版本,他们复制之前的项目,改变一下base_url,然后修改需要修改的接口。这样2个版本同时支持的服务器端就写好了,是不是超级直观?直接运行一下吧。

复制代码
{u\'message\': u\'\\u6210\\u529f\\u767b\\u5f55\', u\'code\': 1, u\'nickname\': u\'\\u6d4b\\u8bd5\\u7528\\u62371\', u\'token\': u\'e5a74170d81feb106a066f18f9f2e966\'}
{u\'phone_number\': u\'13565208554\', u\'code\': 1, u\'nickname\': u\'\\u6d4b\\u8bd5\\u7528\\u62371\'}
{u\'message\': u\'\\u6210\\u529f\\u767b\\u5f55\', u\'code\': 1, u\'nickname\': u\'\\u6d4b\\u8bd5\\u7528\\u62371\', u\'token\': u\'e5a74170d81feb106a066f18f9f2e966\'}
{u\'phone_number\': u\'13565208554\', u\'code\': 1, u\'nickname\': u\'\\u6d4b\\u8bd5\\u7528\\u62371\'}
复制代码

返回的code都是1,两种方式登录都支持。老板要求都达到了,老板高兴,发奖金,我们也高兴(好吧,不做梦了)。

  好了,讲到这,大家应该对整个项目接口有非常清晰的了解了,以后再加接口或者更新版本,对你来说,都是不是问题了吧。

 

摘要: 主要讲述flask的蓝图在restful api中的使用,以及怎么应对版本更新。阅读全文
posted @ 2016-05-24 13:35 月儿弯弯0204 阅读(279) | 评论 (0) 编辑
 
摘要: 任何一个好的程序,配置文件必不可少,而且非常重要。配置文件里存储了连接数据库,redis的用户密码,不允许有任何闪失。要有灵活性,用户可以自己配置;生产环境和开发环境要分开,最好能简单的修改一个东西,就能达到要求;要有安全性,最好的方式,即使有一天前端服务器被窃取信息,配置文件里的信息也不能泄露。 阅读全文
posted @ 2016-05-24 10:19 月儿弯弯0204 阅读(11) | 评论 (0) 编辑
 
摘要: 我们现在开发app,注册用户的时候,不再像web一样,发送到个人邮箱了,毕竟个人邮箱在移动端填写验证都很麻烦,一般都采用短信验证码的方式。今天我们就讲讲这方面的内容。 首先,先找一个平台吧。我们公司找的容联云通讯这个平台,至少目前为止,用的还可以。先在容联上注册一下,然后创建一个应用,如下图所示: 阅读全文
posted @ 2016-05-09 10:53 月儿弯弯0204 阅读(87) | 评论 (0) 编辑
 
摘要: 这是一篇简单介绍七牛云如何使用的文章,主要在restful api过程中,会出现什么样的问题,以及如何解决。阅读全文
posted @ 2016-05-04 17:25 月儿弯弯0204 阅读(344) | 评论 (0) 编辑
 
摘要: 介绍了如何使用alembic来修改数据库阅读全文
posted @ 2016-03-31 08:53 月儿弯弯0204 阅读(376) | 评论 (0) 编辑
 
摘要: 把上一章代码简化了一下,似乎效果很不错呢阅读全文
posted @ 2016-03-28 18:32 月儿弯弯0204 阅读(105) | 评论 (0) 编辑
 
摘要: 这是一篇初步介绍flask的restful api的文章,只是初步文章,后面陆续改进。其中详细介绍了,怎么使用redis在服务器端存储数据方式并且验证。阅读全文
posted @ 2016-03-28 16:01 月儿弯弯0204 阅读(342) | 评论 (1) 编辑
 

以上是关于flask开发restful api的主要内容,如果未能解决你的问题,请参考以下文章

flask restful-api实现及基于flask-httpauth实现基础权限管控

flask restful-api实现及基于flask-httpauth实现基础权限管控

flask开发restful api系列

如何用 flask 优雅的实现 restful api

flask插件系列之flask_restful设计API

flask编写RESTful API