flask-apispec - 快速的去限制请求参数的方法

笪健
2023-12-01

编写接口的时候参数判断非常的头疼

平时在写接口的时候,我们通常会在视图函数中去判断时候有某一个参数,并转换参数类型,这时候会使得视图函数变得非常的笨重,可读性差,使用flask_apispec可以解决这一个问题。

一、安装

pip install flask-apispec

二、使用

1. 限制参数的类型,快速获取参数的值

  • 这里使用一个官方的例子,写的非常的容易理解
from flask import Flask, jsonify
from flask_apispec import use_kwargs, marshal_with

from marshmallow import fields

app = Flask(__name__)

@app.route('/test')
@use_kwargs({'email': fields.Str(), 'is_able': fields.Boolean()})
def test(**kwargs):
	# 从request的 args、form、get_json()中拿到user_kwargs装饰器内存在的key
	# 将获取的key,value放在kwargs参数中去
	print(kwargs)
    return json({'msg': 'test'})

2. 指定返回的数据字段

  • 有时候我们在序列化对象时需要把模型类的值放入字典再返回,flask_apisepc提供了返回指定字段的功能
from flask import Flask
from flask_apispec import use_kwargs, marshal_with

from marshmallow import fields, Schema

from .models import Pet

app = Flask(__name__)


class PetSchema(Schema):
    class Meta:
    	# 指定响应模型的数据字段
        fields = ('name', 'category', 'size')

@app.route('/pets')
@use_kwargs({'category': fields.Str(), 'size': fields.Str()}) # 获取参数到,传到kwargs中去
@marshal_with(PetSchema(many=True))  # many表示可以返回多个Pet,放在一个列表里
# @marshal_with(PetSchema)  # 这样只返回一个数据
def get_pets(**kwargs):
	# 直接返回,不需要再去序列化,当时好像里面不能再加一些像msg这样的数据进去
    return Pet.query.filter_by(**kwargs)

3. locations 限制获取参数的位置

  • use_kwargs方法
def use_kwargs(args, locations=None, inherit=None, apply=None, **kwargs):
	pass

它的实现是使用了webargs的FlaskParser类,来帮助我们获取全局request对象的参数
默认的locations有三个 DEFAULT_LOCATIONS = ("querystring", "form", "json")
locations可以为一个元祖,官方是这么说的

tuple locations: Where on the request to search for values.Can include one or more of 
        ``('json', 'querystring', 'form','headers', 'cookies', 'files')``.

所以说我们可以选用('json', 'querystring', 'form','headers', 'cookies', 'files')作为locations的值

如果我们直接使用use_kwargs时不指定locations参数,还可能会出现一些问题,比如我们想在json中获取的参数,结果querystring中也有而json中没有,这样会拿到querystring的参数,错误的拿到参数

4. 演示

  • post请求,这里使用flask_restful
import re

from marshmallow import fields
from flask_apispec import use_kwargs
from flask_restful import Resource


def valid_phone(phone):
    phone_rule = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$"
    return True if re.match(phone_rule, phone) else False


class TestResource(Resource):
    @use_kwargs({
        "phone": fields.String(required=True, validate=valid_phone),
        "phone_code": fields.String(required=True, validate=lambda phone_code: True if len(phone_code) == 6 else False)
    }, locations=("json", ))
    def post(self, **kwargs):
    	phone = kwargs.get("phone")
    	phone_code = kwargs.get("phone_code")
    	# ...

上面的use_kwargs方法指定了locations=("json", )这样就不会从其他的位置去获取参数了,还有使用marshmallow.fields时,可以使用validate来对参数进行合法性的校验,这样能使得我们的代码看的非常的工整,只用专心去实现逻辑部门的内容。

5. 422 状态码

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>422 Unprocessable Entity</title>
<h1>Unprocessable Entity</h1>
<p>The request was well-formed but was unable to be followed due to semantic errors.</p>

如果前端传来的参数不合法,会出现422的情况,这时候不要着急,核对一下参数类型是否合法,或者后台校验是否有问题

 类似资料: