miLibris / flask-rest-jsonapi

Flask extension to build REST APIs around JSONAPI 1.0 specification.
http://flask-rest-jsonapi.readthedocs.io
MIT License
597 stars 153 forks source link

Unable to pass filter parameters while using oauthlib #42

Closed zengoma closed 7 years ago

zengoma commented 7 years ago

Hey. I've picked up an issue while trying to pass filter params while using flask-oauthlib. This is not an issue with flask-rest-jsonapi, but with the oauthlib 2.0.2 library. I am however giving you a heads up as it directly affects the functioning of this package. When trying to pass the following characters in "{}[]" in filter request you will recieve the following error:

127.0.0.1 - - [21/May/2017 07:44:58] "GET /api/products?filter=[{%22name%22:%22owner%22,%22op%22:%22has%22,%22val%22:%20{%22name%22:%22id%22,%22op%22:%22eq%22,%22val%22:1}}] HTTP/1.1
" 500 -
Traceback (most recent call last):
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "C:\projects\pythonapi\venv\lib\site-packages\flask_cors\extension.py", line 161, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\_compat.py", line 33, in reraise
    raise value
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\projects\pythonapi\venv\lib\site-packages\flask_cors\extension.py", line 161, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\_compat.py", line 33, in reraise
    raise value
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:\projects\pythonapi\venv\lib\site-packages\flask\views.py", line 84, in view
    return self.dispatch_request(*args, **kwargs)
  File "C:\projects\pythonapi\venv\lib\site-packages\flask_rest_jsonapi\resource.py", line 66, in dispatch_request
    raise e
  File "C:\projects\pythonapi\venv\lib\site-packages\flask_rest_jsonapi\resource.py", line 59, in dispatch_request
    response = method(*args, **kwargs)
  File "C:\projects\pythonapi\venv\lib\site-packages\flask_rest_jsonapi\decorators.py", line 32, in wrapped
    return func(*args, **kwargs)
  File "C:\projects\pythonapi\venv\lib\site-packages\flask_oauthlib\provider\oauth2.py", line 555, in decorated
    valid, req = self.verify_request(scopes)
  File "C:\projects\pythonapi\venv\lib\site-packages\flask_oauthlib\provider\oauth2.py", line 483, in verify_request
    uri, http_method, body, headers, scopes
  File "C:\projects\pythonapi\venv\lib\site-packages\oauthlib\oauth2\rfc6749\endpoints\base.py", line 64, in wrapper
    return f(endpoint, uri, *args, **kwargs)
  File "C:\projects\pythonapi\venv\lib\site-packages\oauthlib\oauth2\rfc6749\endpoints\resource.py", line 68, in verify_request
    request = Request(uri, http_method, body, headers)
  File "C:\projects\pythonapi\venv\lib\site-packages\oauthlib\common.py", line 417, in __init__
    self._params.update(dict(urldecode(self.uri_query)))
  File "C:\projects\pythonapi\venv\lib\site-packages\oauthlib\common.py", line 131, in urldecode
    raise ValueError(error % (set(query) - urlencoded, query))
ValueError: Error trying to decode a non urlencoded string. Found invalid characters: {']', '[', '}', '{'} in the string: 'filter=[{%22name%22:%22owner%22,%22op%22:%22has%22,%22val%2
2:%20{%22name%22:%22id%22,%22op%22:%22eq%22,%22val%22:1}}]'. Please ensure the request/response body is x-www-form-urlencoded.

I managed to resolve the issue by modifying oauthlib and have created a pull request here: https://github.com/idan/oauthlib/pull/477 . Anyone wanting to continue development may implement this until it hopefully gets pulled into the master.

akira-dev commented 7 years ago

I think there is no problem with oauthlib, the problem is that your querystring is not correctly urlencoded. Try this: filter=%5B%7B%22name%22%3A+%22owner%22%2C+%22val%22%3A+%7B%22name%22%3A+%22id%22%2C+%22val%22%3A+1%2C+%22op%22%3A+%22eq%22%7D%2C+%22op%22%3A+%22has%22%7D%5D and tell me if it solves your problem

You must use urlencode from urllib to generate your querystring. Example:

>>> s = [{"name":"owner","op":"has","val":{"name":"id","op":"eq","val":1}}]
>>> import json
>>> j = json.dumps(s)
>>> result = {"filter": j}
>>> urlencode(result)
'filter=%5B%7B%22name%22%3A+%22owner%22%2C+%22val%22%3A+%7B%22name%22%3A+%22id%22%2C+%22val%22%3A+1%2C+%22op%22%3A+%22eq%22%7D%2C+%22op%22%3A+%22has%22%7D%5D'
zengoma commented 7 years ago

@akira-dev You're right, I am an idiot. I should have just read the first line of the stack trace. I just assumed that postman was url-encoding automatically. Cancelling the pull request. Thank you!