Skip to content

Instantly share code, notes, and snippets.

@abathur
Last active March 30, 2019 18:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abathur/5d9de7c2adbbd3f2c85e50e5f81fb267 to your computer and use it in GitHub Desktop.
Save abathur/5d9de7c2adbbd3f2c85e50e5f81fb267 to your computer and use it in GitHub Desktop.
Flask-Restplus error-handling interop issues (see https://github.com/noirbizarre/flask-restplus/issues/340)

I've included a minimal server example and 3 request/response logs. The server code sets a trace for exception events to pull out exceptions that restplus is swallowing (unfortunately this is a little spammy, since there's a trace event every step up the stack). FWIW, running this in Python 2.7.12.

log_clean_get

Nothing significant here. Just demonstrating that everything works for an undecorated endpoint.

log_post_without_auth_header

Requesting the @jwt_required post endpoint without an auth header raises this error: NoAuthorizationError: Missing Authorization Header

I've registered log_unauth_exceptions as a restplus error handler for NoAuthorizationError, but don't correctly return a Flask response. This potential user mistake is hard to figure out without seeing the exception in restplus that gets swallowed in the error-handling and is only visible via the exception trace:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 589, in handle_error
    default_data['message'] = default_data.get('message', str(e))
AttributeError: 'NoneType' object has no attribute 'get'

log_post_with_expired_token

In this example, I first request a new token that immediately expires, and then attempt to use it to access the post endpoint. The response from Flask for this case should get passed to the expired_token_response method decorated with @jwt.expired_token_loader, but the error-handling in restplus never passes the call back to the primary Flask error-handling routine. Restplus instead returns the incorrect/uninformative default internal server error (though it does log the correct error).

CLI:
curl -k -X GET --header 'Content-Type: application/json' --header 'Accept: application/json' 'http://localhost:5000/api/1.0/products/access'
RESPONSE:
""
SERVER LOG:
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 964, in __getitem__
raise KeyError()
KeyError
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 1129, in __contains__
self.__getitem__(key, _get_mode=True)
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 964, in __getitem__
raise KeyError()
KeyError
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/lib/python2.7/encodings/__init__.py", line 145, in search_function
codecaliases = mod.getaliases()
AttributeError: 'module' object has no attribute 'getaliases'
----------[ end debug exception ]----------
10.0.2.2 - - [18/Oct/2017 14:47:20] "GET /api/1.0/products/access HTTP/1.1" 200 -
CLI:
curl -k -X GET --header 'Content-Type: application/json' --header 'Accept: application/json' 'http://localhost:5000/token'
RESPONSE:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI4Yjg0NmZmNS1hMGJkLTQ5ZDAtYTQ1YS00ZDIzYTM3YThiYmQiLCJleHAiOjE1MDgzMzk0NzMsImZyZXNoIjpmYWxzZSwiaWF0IjoxNTA4MzM5NDczLCJ0eXBlIjoiYWNjZXNzIiwibmJmIjoxNTA4MzM5NDczLCJpZGVudGl0eSI6InRlc3QifQ.uADJ6GnxMZ48NgDtX7_AVEumJW3ZYgR0_nHesXHLyC8
CLI:
curl -k -X POST --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI4Yjg0NmZmNS1hMGJkLTQ5ZDAtYTQ1YS00ZDIzYTM3YThiYmQiLCJleHAiOjE1MDgzMzk0NzMsImZyZXNoIjpmYWxzZSwiaWF0IjoxNTA4MzM5NDczLCJ0eXBlIjoiYWNjZXNzIiwibmJmIjoxNTA4MzM5NDczLCJpZGVudGl0eSI6InRlc3QifQ.uADJ6GnxMZ48NgDtX7_AVEumJW3ZYgR0_nHesXHLyC8' --header 'Content-Type: application/json' --header 'Accept: application/json' 'http://localhost:5000/api/1.0/products/access'
RESPONSE:
{
"message": "Internal Server Error"
}
SERVER LOG:
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 90, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/tokens.py", line 98, in decode_jwt
data = jwt.decode(encoded_token, secret, algorithms=[algorithm])
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 90, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 153, in _decode_jwt_from_headers
identity_claim=config.identity_claim
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/tokens.py", line 98, in decode_jwt
data = jwt.decode(encoded_token, secret, algorithms=[algorithm])
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 90, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 153, in _decode_jwt_from_headers
identity_claim=config.identity_claim
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/tokens.py", line 98, in decode_jwt
data = jwt.decode(encoded_token, secret, algorithms=[algorithm])
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 90, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 153, in _decode_jwt_from_headers
identity_claim=config.identity_claim
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/tokens.py", line 98, in decode_jwt
data = jwt.decode(encoded_token, secret, algorithms=[algorithm])
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 90, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 153, in _decode_jwt_from_headers
identity_claim=config.identity_claim
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/tokens.py", line 98, in decode_jwt
data = jwt.decode(encoded_token, secret, algorithms=[algorithm])
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 90, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 153, in _decode_jwt_from_headers
identity_claim=config.identity_claim
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/tokens.py", line 98, in decode_jwt
data = jwt.decode(encoded_token, secret, algorithms=[algorithm])
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 90, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 313, in wrapper
resp = resource(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 153, in _decode_jwt_from_headers
identity_claim=config.identity_claim
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/tokens.py", line 98, in decode_jwt
data = jwt.decode(encoded_token, secret, algorithms=[algorithm])
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 90, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 313, in wrapper
resp = resource(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 153, in _decode_jwt_from_headers
identity_claim=config.identity_claim
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/tokens.py", line 98, in decode_jwt
data = jwt.decode(encoded_token, secret, algorithms=[algorithm])
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 90, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[ end debug exception ]----------
--------------------------------------------------------------------------------
ERROR in app [/usr/local/lib/python2.7/dist-packages/flask/app.py:1560]:
Exception on /api/1.0/products/access [POST]
--------------------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 313, in wrapper
resp = resource(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 153, in _decode_jwt_from_headers
identity_claim=config.identity_claim
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/tokens.py", line 98, in decode_jwt
data = jwt.decode(encoded_token, secret, algorithms=[algorithm])
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 90, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 120, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 161, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
ExpiredSignatureError: Signature has expired
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 965, in __getitem__
raise exceptions.BadRequestKeyError(key)
BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 1114, in pop
rv = self[key]
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 965, in __getitem__
raise exceptions.BadRequestKeyError(key)
BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 964, in __getitem__
raise KeyError()
KeyError
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 1129, in __contains__
self.__getitem__(key, _get_mode=True)
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 964, in __getitem__
raise KeyError()
KeyError
----------[ end debug exception ]----------
10.0.2.2 - - [18/Oct/2017 15:12:13] "POST /api/1.0/products/access HTTP/1.1" 500 -
CLI:
curl -k -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' 'http://localhost:5000/api/1.0/products/access'
RESPONSE:
{
"message": "Internal Server Error"
}
SERVER LOG:
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 1349, in __getitem__
return _unicodify_header_value(self.environ['HTTP_' + key])
KeyError: ('HTTP_AUTHORIZATION',)
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 1003, in get
rv = self.__getitem__(key, _get_mode=True)
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 1349, in __getitem__
return _unicodify_header_value(self.environ['HTTP_' + key])
KeyError: ('HTTP_AUTHORIZATION',)
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 132, in _decode_jwt_from_headers
raise NoAuthorizationError("Missing {} Header".format(header_name))
NoAuthorizationError: Missing Authorization Header
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 132, in _decode_jwt_from_headers
raise NoAuthorizationError("Missing {} Header".format(header_name))
NoAuthorizationError: Missing Authorization Header
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 132, in _decode_jwt_from_headers
raise NoAuthorizationError("Missing {} Header".format(header_name))
NoAuthorizationError: Missing Authorization Header
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 132, in _decode_jwt_from_headers
raise NoAuthorizationError("Missing {} Header".format(header_name))
NoAuthorizationError: Missing Authorization Header
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 132, in _decode_jwt_from_headers
raise NoAuthorizationError("Missing {} Header".format(header_name))
NoAuthorizationError: Missing Authorization Header
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 313, in wrapper
resp = resource(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 132, in _decode_jwt_from_headers
raise NoAuthorizationError("Missing {} Header".format(header_name))
NoAuthorizationError: Missing Authorization Header
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 313, in wrapper
resp = resource(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 35, in wrapper
jwt_data = _decode_jwt_from_request(request_type='access')
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 203, in _decode_jwt_from_request
decoded_token = _decode_jwt_from_headers()
File "/usr/local/lib/python2.7/dist-packages/flask_jwt_extended/view_decorators.py", line 132, in _decode_jwt_from_headers
raise NoAuthorizationError("Missing {} Header".format(header_name))
NoAuthorizationError: Missing Authorization Header
----------[ end debug exception ]----------
really useful log message
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 589, in handle_error
default_data['message'] = default_data.get('message', str(e))
AttributeError: 'NoneType' object has no attribute 'get'
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 554, in error_router
return self.handle_error(e)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 589, in handle_error
default_data['message'] = default_data.get('message', str(e))
AttributeError: 'NoneType' object has no attribute 'get'
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1504, in handle_user_exception
assert exc_value is e
AssertionError
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 557, in error_router
return original_handler(e)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1504, in handle_user_exception
assert exc_value is e
AssertionError
----------[ end debug exception ]----------
--------------------------------------------------------------------------------
ERROR in app [/usr/local/lib/python2.7/dist-packages/flask/app.py:1560]:
Exception on /api/1.0/products/access [POST]
--------------------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python2.7/dist-packages/flask_restplus/api.py", line 557, in error_router
return original_handler(e)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1504, in handle_user_exception
assert exc_value is e
AssertionError
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 965, in __getitem__
raise exceptions.BadRequestKeyError(key)
BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 1114, in pop
rv = self[key]
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 965, in __getitem__
raise exceptions.BadRequestKeyError(key)
BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 964, in __getitem__
raise KeyError()
KeyError
----------[ end debug exception ]----------
----------[start debug exception]----------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 1129, in __contains__
self.__getitem__(key, _get_mode=True)
File "/usr/local/lib/python2.7/dist-packages/werkzeug/datastructures.py", line 964, in __getitem__
raise KeyError()
KeyError
----------[ end debug exception ]----------
10.0.2.2 - - [18/Oct/2017 14:48:35] "POST /api/1.0/products/access HTTP/1.1" 500 -
Flask==0.12.2
flask-restplus==0.10.1
Flask-JWT-Extended==3.3.1
import traceback, sys
from datetime import timedelta
from flask import Flask, Blueprint
from flask_jwt_extended import jwt_required, JWTManager, create_access_token
from flask_restplus import Api, Namespace, Resource
# setup flask, jwt
app = Flask(__name__)
app.config['SECRET_KEY'] = "test"
jwt = JWTManager(app)
# make an immediately-expiring dummy token
@app.route("/token")
def token():
return create_access_token(identity="test", expires_delta=timedelta())
# trace/print all exceptions
def print_all_exceptions(frame, event, arg):
if event.endswith("exception"):
print("----------%s----------" % "[start debug exception]")
traceback.print_exception(*arg)
print("----------%s----------" % "[ end debug exception ]")
return print_all_exceptions
@app.before_request
def set_trace():
sys.settrace(print_all_exceptions)
@app.teardown_request
def unset_trace(request):
sys.settrace(None)
return request
# setup restplus api
api = Blueprint('api', __name__, url_prefix="/api")
v1 = Api(
api,
prefix='/1.0',
title='My Title',
version='1.0',
description='A description',
)
products = v1.namespace('products', description='Product related operations')
@products.route('/access')
class ProductAccess(Resource):
@jwt_required #
def post(self):
return "", 200
def get(self):
return "", 200
from flask_jwt_extended.exceptions import JWTExtendedException, NoAuthorizationError
@jwt.expired_token_loader
def expired_token_response(reason):
return reason, 401
@v1.errorhandler(NoAuthorizationError)
def log_unauth_exceptions(exception):
print("really useful log message")
# we were supposed to return a flask response, but we think documentation is for chumps
# connect, run
app.register_blueprint(api)
app.run(host='0.0.0.0', port=5000, debug=True, threaded=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment