Repository: marshmallow-code/webargs

Issue:
Parsing arguments always returns None
parsing the arguments always returns None, even if trying the most basic syntax taken from the [quick start page](https://webargs.readthedocs.io/en/latest/quickstart.html#basic-usage). Maybe I have a typo I failed to see.

Versions:
Flask: 1.1.2
Marshmallow: 3.6.0
Flask-marshmallow: 0.12
webargs: 6.1.0

Code:
```python
from pprint import pprint

from flask import request
from flask_restful import Resource
from webargs import fields, validate
from webargs.flaskparser import parser

# Flask-restful resource, GET method called with ?type=99999
class WebsiteList(Resource):
    @classmethod
    # @use_kwargs(website_args)
    def get(cls):
        website_args = {
            'type': fields.String(
                required=True,
                validate=validate.Range(min=0, max=6, error="testing error, never triggered")
            ),
        }

        # Line below outputs: ImmutableMultiDict([('type', '6')])
        pprint(request.args)

        args = parser.parse(website_args, request)
        # Line below outputs: None
        pprint(args)
```

I have also tried the decorator @use_kwargs(website_args) (And define website_args beforehand of course), but I get a traceback for TypeError: 'NoneType' object is not iterable:
```python
Traceback (most recent call last):
  File "C:\Users\Marco\.virtualenvs\api-kHflOUBu\lib\site-packages\flask\app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\Marco\.virtualenvs\api-kHflOUBu\lib\site-packages\flask\app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:\Users\Marco\.virtualenvs\api-kHflOUBu\lib\site-packages\flask_restful\__init__.py", line 468, in wrapper
    resp = resource(*args, **kwargs)
  File "C:\Users\Marco\.virtualenvs\api-kHflOUBu\lib\site-packages\flask\views.py", line 89, in view
    return self.dispatch_request(*args, **kwargs)
  File "C:\Users\Marco\.virtualenvs\api-kHflOUBu\lib\site-packages\flask_restful\__init__.py", line 583, in dispatch_request
    resp = meth(*args, **kwargs)
  File "C:\Users\Marco\.virtualenvs\api-kHflOUBu\lib\site-packages\webargs\core.py", line 364, in wrapper
    args, kwargs, parsed_args, as_kwargs
  File "C:\Users\Marco\.virtualenvs\api-kHflOUBu\lib\site-packages\webargs\core.py", line 298, in _update_args_kwargs
    kwargs.update(parsed_args)
TypeError: 'NoneType' object is not iterable
```


Discussion:
The location defaults to `json` while you're passing query args. You should specify the location explicitly to the parser (see the docs): https://webargs.readthedocs.io/en/latest/quickstart.html#request-locations.

However, you should get an empty dict, not `None`. Or more likely a `ValidationError` because the field is required.

Do you think you could provide an example without external dependencies?

By the way, Range validator is meant for numbers. You should use a Length validator.


Thanks for your answer! The `Range` validator was just to try to trigger an error, I was aware and only wanted to get some response instead of the exception.

Tried setting the location, I had no idea webargs used others than query string, I guess I should have guessed!

Using the location, it works when using `args = parser.parse(website_args, request, location='query')`, however `@use_kwargs(website_args, location='query')` still triggers the error. I don't think I can provide an example without  the external dependencies as everything is deeply coupled (I'm still new with Flask and Marshmallow), but I could give you a zip file with the whole project, you should easily be able to launch it using the pipfile and call the endpoint triggering the error if you wish.
Don't bother. If I get the time to investigate this, I find it easier to create a virtualenv, install your dependencies and launch the code above.
Ok! Let me know if you need anything else, I'll use something else in the meantime :)
I just took a crack at reproducing this issue without flask-restful and I looked at flask-restful source to see if there was anything obvious they're doing which might trip us up.

<details><summary>this example, very similar to the provided one, works and fails with a 422</summary>

```python
from flask import Flask

from webargs.flaskparser import parser
import marshmallow as ma

website_args = {"type": ma.fields.String(required=True)}

app = Flask(__name__)


@app.route("/func_1")
def func_1():
    print("func_1: start")
    res = parser.parse(website_args)
    print("func_1: parse done")
    print("func_1: res:" + str(res))
    print("func_1: stop")


with app.test_client() as client:
    res = client.get("/func_1")
    print("post_req: status=" + str(res.status_code))
    print("post_req: data:\n" + res.data.decode("utf-8"))
```
</details>

I've tried a few variations on this theme with just flask and webargs.

It's possible that flask-restful is doing something wrong or just unexpected, but my suspicion is that in the OP's case, `flask.abort` or `parser._on_validation_error` aren't causing exceptions to be raised. Possibly flask-restful changes the behavior of `abort`? I'm not familiar enough with the framework to say.

I went back over our empty and null body handling for JSON data, and everything seems to lead back to the JSON data being `missing`, and we later convert that to `{}` to pass to the schema.
But one thing I noticed is that the fallthrough condition for `parse` could produce `None`, if the user has defined an error handler which doesn't raise an exception. I think this is what's going on.

Resolving patch:
diff --git a/src/webargs/core.py b/src/webargs/core.py
--- a/src/webargs/core.py
+++ b/src/webargs/core.py
@@ -269,6 +269,10 @@ def parse(
                 error_status_code=error_status_code,
                 error_headers=error_headers,
             )
+            warnings.warn(
+                "_on_validation_error hook did not raise an exception and flow "
+                "of control returned to parse(). You may get unexpected results"
+            )
         return data
 
     def get_default_request(self):


Test patch: