9

I'm using the flask-restful, and I'm having trouble constructing a RequestParser that will validate a list of only integers. Assuming an expected JSON resource format of the form:

{
    'integer_list': [1,3,12,5,22,11, ...] # with a dynamic length
}

... and one would then create a RequestParser using a form something like:

from flask.ext.restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('integer_list', type=list, location='json')

... but how can i validate is an integer list?

Ricardo
  • 7,921
  • 14
  • 64
  • 111

5 Answers5

39

You can use action='append'. For example:

parser.add_argument('integer_list', type=int, action='append')

Pass multiple integer parameters:

curl http://api.example.com -d "integer_list=1" -d "integer_list=2" -d "integer_list=3"

And you will get a list of integers:

args = parser.parse_args()
args['integer_list'] # [1, 2, 3]

An invalid request will automatically get a 400 Bad Request response.

oferei
  • 1,610
  • 2
  • 19
  • 27
  • Great answer. Kind of strange to use a curl invocation as an example, though. Pretty much everyone is going to be interested in a standard url. Example: http://www.example.com/v1/user/?id=1&id=2 – melchoir55 Feb 18 '17 at 05:35
  • 1
    It's not the usual use case, but it's an easy way to unitest your code. – oferei Feb 19 '17 at 10:14
3

You cannot in fact. Since you can pass a list with multiple kinds of types, e.g. [1, 2, 'a', 'b'], with reqparser, you can only parse with type=list. You need to check the elements of the list one by one by yourself. The code looks like below:

parse_result = parser.add_argument('integer_list', type=list, location='json')
your_list = parse_result.get('integer_list', [])
for element in your_list: 
    if isinstance(element, int): 
        # do something
        print "element is int"
    else:
        # do something else
        print "element is not int"
Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144
Eric
  • 71
  • 1
  • 5
  • The asker asked about json data not form data, so in this case, we can only check the the list type like below, then when we get the list, we need to check the element one by one, I add example code. – Eric May 31 '17 at 02:32
  • @Ajean At the time I reviewed this answer it was nothing more than a comment and didn't provide any new information. – Uyghur Lives Matter May 31 '17 at 14:06
2

You need to use the 'append' action.

from flask.ext.restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('integer_list', type=int, action="append", location='json')

args = parser.parse_args()

list_of_int = args['integer_list']
Eldad
  • 21
  • 2
-1

You can check types with isinstance, here you set the type to int (integer).

This would work like this:

a=1    
isinstance(a,int)

evaluates to TRUE

To check this for a whole list use all(). and loop through the list with the for loop so every element of the list gets checked.

if all(isinstance(x,int) for x in integer_list):
    parser.add_argument('integer_list', type=list, location='json')

In your case this should evaluate to TRUE if all elements are integers and executes the code in the for loop

vds
  • 349
  • 1
  • 10
  • I have a similar workaround, I was looking for anything that could I have misread in docs. Anyway i will upvote you. – Ricardo Jan 03 '15 at 20:52
  • How can I iterate over integer_list without defining it? NameError: global name 'integer_list' is not defined. – Hussain Jul 13 '15 at 07:57
  • This answer clearly misses the point of the question. The OP is trying to use the `parser` to get `integer_list`. Requiring `integer_list` to be defined to know how to parse itself is incorrect. – Chris Nov 29 '16 at 20:20
  • This works only in flask_restful 0.3.5 and below, for 0.3.6 the only thing that works is answer given by @oferei at the bottom (int with action='append') – ARA1307 Nov 30 '17 at 02:27
-1

Same issue occurred. I looked into the source code, and found Argument.type is mainly used in the situation self.type(value). So you can hack this like me:

parser.add_argument('integer_list', type=json.loads, location='json')

It's not what it supposed to do, but works.

Kane Blueriver
  • 4,170
  • 4
  • 29
  • 48