Search code examples
pythonflaskmarshmallowwebargs

Flask, Marshmallow 3, and webargs use_args fails to parse arguments


With Flask 1.1.2, marshmallow 3.6.1 and webargs 6.1.0 all of my arguments are always missing.

Schema:

class ExportSearchSchema(Schema):
    limit = fields.Integer(required=False, allow_none=False, default=10, missing=10)
    offset = fields.Integer(required=False, allow_none=False, default=0, missing=0)
    status = fields.Str(required=False)

    class Meta:
        unknown = RAISE

    @validates('status')
    def validate_status(self, value):
        if value and value not in ['complete', 'pending', 'failed']:
            raise ValidationError('Invalid status: {}'.format(value))

    @validates('limit')
    def validate_limit(self, value):
        if value > 100:
            raise ValidationError('Max limit is 100')
        if value < 1:
            raise ValidationError('Limit must be a positive number and less than 100')

    @validates('offset')
    def validate_offset(self, value):
        if value < 0:
            raise ValidationError('Offset must be equal to, or greater than 0')

blueprint.py:

from flask import jsonify, Response
from flask import Blueprint
from marshmallow import Schema, fields, validates, ValidationError, RAISE
from webargs.flaskparser import use_args

exports = Blueprint('exports', __name__)

@exports.route('exports/',
               methods=['GET'], strict_slashes=False)
@use_args(ExportSearchSchema(unknown=RAISE))
def get_export_list(qparams):
  log.info("qparams {}".format(qparams)
  response = jsonify({'data': 'export_list'})
  response.mimetype = 'application/json'
  return response

When I curl any value for limit or offset it always uses the default value.

curl http://localhost:8000/exports?limit=5930

log: "qparams {'limit': 10, 'offset': 0}"}

I expect a ValidationError to be raised because the limit should be > 100.

When I curl an unknown parameter I expect a ValidationError to be raised because it's an unknown parameter. This also does not work as expected.

curl http://localhost:8000/exports?lkfjdskl=fkjdsl

returns a 200 and has no qparams.

What am I doing wrong here in combining webargs, Flask, and marshmallow?


Solution

  • The logic changed in webargs 6.

    Before webargs 6, the parser would iterate over the fields of the schema and, by default, search over multiple locations to find the value.

    In webargs 6, the parser just passes the data from a single location to the schema. The location defaults to "json".

    Since you're using query arguments, you need to specify it explicitly:

    @use_args(ExportSearchSchema(unknown=RAISE), location="query")
    

    Since you don't specify the location, json body is assumed, nothing is found, and the default values are used.

    This is documented in webargs docs: "upgrading to 6.0".