15

我正在尝试将 API 公开给各种请求方法(GET、url x-www-form-urlencoded POST 和 json POST):

@app.route('/create', methods=['GET', 'POST'])
def create_file():
    if request.method == 'GET':
        n = request.args.get('n')
        t = request.args.get('t')
    if request.method == 'POST':
        if request.json:
            n = request.json['n']
            t = request.json['t']
        else:
            n = request.form['n']
            t = request.form['t']
    try:
        n = int(n)
    except:
        n = 1
    ...

上面的内容显得过于冗长。有没有更简单或更好的写法?谢谢。

4

5 回答 5

22

这看起来更好吗?如果您可以接受将 JSON POST 请求移动到不同的路线(无论如何您确实应该这样做),我认为这会更干净一些。

def _create_file(n, t):
    try:
        n = int(n)
    except:
        n = 1
    ...

@app.route('/create')
def create_file():
    n = request.args.get('n')
    t = request.args.get('t')
    return _create_file(n, t)

@app.route('/create', methods = ['POST'])
def create_file_form():
    n = request.form.get('n')
    t = request.form.get('t')
    return _create_file(n, t)

@app.route('/api/create', methods = ['POST'])
def create_file_json():
    if not request.json:
        abort(400); # bad request
    n = request.json.get('n')
    t = request.json.get('t')
    return _create_file(n, t)
于 2013-07-18T17:21:25.470 回答
4

没有什么可以阻止您将代码重写为:

@app.route('/create', methods=['GET', 'POST'])
def create_file():
    params = None
    if request.method == 'GET':
        params = request.args
    if request.method == 'POST':
        if request.json:
            params = request.json
        else:
            params = request.form

    n = params.get('n')
    t = params.get('t')

    try:
        n = int(n)
    except:
        n = 1
    ...
于 2013-07-18T11:18:05.060 回答
1

按照其他人的建议使用Flask-Restful扩展。然后,您可以执行以下操作:

class CreateFile(Resource):
    def get(self):
       args = parser.parse_args()
       n,t = args['n'], args['t']

    def post(self, todo_id):
       # do post stuff

等等...

于 2013-07-18T18:28:15.367 回答
0

我不知道这是否是您正在寻找的,因为您已经接受了答案,但是您可以通过应用标准重构技术来消除很多冗长的内容。首先,每个功能的单一职责:

@app.route('/create', methods=['GET', 'POST'])
def create_file():
    n, t = get_nt_request_data()
    return process_n(n)

def get_nt_request_data():
    if request.method == 'GET':
        return get_nt_query_params()
    if request.method == 'POST':
        if request.json:
            return get_nt_json()
        else:
            return get_nt_form()
    return n, t

def get_nt_query_params():
    n = request.args.get('n')
    t = request.args.get('t')
    return n, t

def get_nt_json():
    n = request.json['n']
    t = request.json['t']
    return n, t

def get_nt_form():
    n = request.form['n']
    t = request.form['t']
    return n, t

def process_n(n):
    try:
        n = int(n)
    except:
        n = 1

现在,这肯定不会更短,但我个人认为它更清晰。每个单独的功能都有明确定义的目的,并且不会混乱。我个人会将 "n, t" 变成一个具有两个字段的对象,但这完全取决于您以及您的应用程序的工作原理。第2步:我们在那里有一些非常明显的复制/粘贴。让我们把它清理干净。

@app.route('/create', methods=['GET', 'POST'])
def create_file():
    n, t = get_nt_request_data()
    return process_n(n)

def get_nt_request_data():
    if request.method == 'GET':
        return get_nt_query_params()
    if request.method == 'POST':
        if request.json:
            return get_nt_json()
        else:
            return get_nt_form()
    return n, t

def get_nt_query_params():
    return build_nt(request.args)

def get_nt_json():
    return build_nt(request.json)

def get_nt_form():
    return build_nt(request.form)

def build_nt(resource):
    return resource.get("n"), resource.get("t")

def process_n(n):
    try:
        n = int(n)
    except:
        n = 1

现在我们正在取得进展!但是,如果我们对 20 个不同的资源执行此操作(假设您的不同端点遵循类似的 HTTP 动词规则),我们将拥有一堆 get_xx_request_data 函数,它们基本上都做同样的事情。让我们参数化!

@app.route('/create', methods=['GET', 'POST'])
def create_file():
    n, t = get_request_data(build_nt)
    return process_n(n)

def build_nt(resource):
    return resource.get("n"), resource.get("t")

def process_n(n):
    try:
        n = int(n)
    except:
        n = 1

# in a shared module somewhere
def get_request_data(builder):
    if request.method == 'GET':
        return builder(request.args)
    if request.method == 'POST':
        if request.json:
            return builder(request.json)
        else:
            return builder(request.form)
    return n, t

端点只需 11 行代码,以及一个您可以为其他人重用的共享函数。(我认为这在概念上类似于可用框架最终所做的事情;我没有机会检查它们。)

最后一点:创建一个带有 GET 请求的文件会让你大吃一惊,并且可能会出现一些奇怪的错误,这取决于你对客户端和干预代理的控制程度。GET 应该是幂等的,因此客户端应该能够在不期望服务器上的任何状态更改的情况下随意重试它们(并且创建某些东西肯定是状态更改)。理论上,代理应该能够在网络中断后重播 GET 命令,甚至无需告诉原始客户端它尝试了两次,但实际上这从未给我带来麻烦。

于 2014-05-28T04:49:24.527 回答
0

想出一个这样的想法:

from flask import request


class RestfulService:

    __method_init_info__ = 'method is not defined yet'

    @classmethod
    def execute(cls):
        if request.method == 'GET':
            return cls.get()
        elif request.method == 'POST':
            return cls.post()
        elif request.method == "PUT":
            return cls.put()
        elif request.method == "DELETE":
            return cls.delete()

    @classmethod
    def get(cls):
        return [cls.__method_init_info__]

    @classmethod
    def post(cls):
        return [cls.__method_init_info__]

    @classmethod
    def put(cls):
        return [cls.__method_init_info__]

    @classmethod
    def delete(cls):
        return [cls.__method_init_info__]

如何使用:

class YourService(RestfulService):
    @classmethod
    def get(cls):
        # do your jobs here
        return []


@api.route('/project', methods=["GET","POST","PUT","DELETE"])
def jobs():
    res = YourService.execute()
    return res

于 2021-10-11T02:57:47.430 回答