Validation not working for reqparse.RequestParser() when there are multiple items by action=append
Code
from flask import Flask
from flask_restx import Api, Resource, reqparse
from flask_restx.inputs import regex
app = Flask(__name__)
api = Api(app)
parser = reqparse.RequestParser(bundle_errors=True)
parser.add_argument('ip_addr',
type=regex(r"^\d+\.\d+\.\d+\.\d+$"),
action="append")
@api.route('/')
class Test(Resource):
@api.expect(parser, validate=True)
def get(self):
return {}
app.run(host="0.0.0.0", debug=True)
Repro Steps (if applicable)
This is a simple app to get multiple IP addresses from clients. As you can run/see, you can append multiple IP addresses.
- Put "1.1.1.1" to execute, it works fine
- Put "1.1.1.1" and "2.2.2.2", validation fails
Expected Behavior
I define type=regex(r"^\d+\.\d+\.\d+\.\d+$") and action="append". I think each text boxes should be treated as IP address.
Actual Behavior
Looks like regex validation happens against aggregated input such as 1.1.1.1\n2.2.2.2.
Error Messages/Stack Trace
JavaScript says Value must follow pattern ^\d+\.\d+\.\d+\.\d+$
Environment
- Python version: 3.8
- Flask version: 2.1.2
- Flask-RESTX version: 0.5.1
- Other installed Flask extensions
Additional Context
I've read https://flask-restx.readthedocs.io/en/latest/parsing.html but didn't find any special information about append. Similar issues happen not only for regex but for int_range too.
This is swagger.json if it helps.
{
"swagger": "2.0",
"basePath": "/",
"paths": {
"/": {
"get": {
"responses": {
"200": {
"description": "Success"
}
},
"operationId": "get_test",
"parameters": [
{
"name": "ip_addr",
"in": "query",
"type": "array",
"pattern": "^\\d+\\.\\d+\\.\\d+\\.\\d+$",
"items": {
"type": "string"
},
"collectionFormat": "multi"
}
],
"tags": [
"default"
]
}
}
},
"info": {
"title": "API",
"version": "1.0"
},
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"tags": [
{
"name": "default",
"description": "Default namespace"
}
],
"responses": {
"ParseError": {
"description": "When a mask can't be parsed"
},
"MaskError": {
"description": "When any error occurs on mask"
}
}
}
@hnakamitsu Not sure if you found a solution or not to this, but if not, you can define a custom function for your request parser that simply returns a ValueError if invalid. You also need to make a call to parse_args() in your endpoint for the validation to run. @api.expect(parser, validate=True) only validates the fields are correct, not the values inside them.
I think something like this is what you are trying to do?
from flask import Flask
from flask_restx import Api, Resource, reqparse
import re
app = Flask(__name__)
api = Api(app)
def safe_ip_addr(name):
"""Valide IP address is valid format"""
if not re.compile(r"^\d+\.\d+\.\d+\.\d+$").match(name):
raise ValueError(f"'{name}' is not a valid IP address.")
return name
parser = reqparse.RequestParser(bundle_errors=True)
parser.add_argument('ip_addr',
type=safe_ip_addr,
action="append")
@api.route('/regex')
class Test(Resource):
@api.expect(parser, validate=True)
def get(self):
# Need to call parse to run the arg parser.
x = parser.parse_args()
return x, 200
app.run(host="0.0.0.0", debug=True)