flask-restx
flask-restx copied to clipboard
405 Method Not Allowed on a namespace route give Internal Server Error
Hi All,
I am getting a weird issue! I am new to python and the flask + flast-restx framework. Can someone please help me understand what I am doing wrong here.
Code01
from flask import Flask, jsonify, request
from flask_restx import Resource, Api
app = Flask(__name__)
api = Api(
app, version='1.0', title='TodoMVC API',
description='A simple TodoMVC API',
)
#ns = api.namespace('todos', description='TODO operations')
@app.errorhandler(404)
def page_not_found(e):
msg = f"The requested URL path {request.path} was not found on the server."
return jsonify(error=msg), 404
@app.errorhandler(405)
def method_not_allowed(e):
msg = f"The requested method '{request.method}' is not allowed."
return jsonify(error=msg), 405
@api.route('/todos')
class RepositoryApi(Resource):
'''Shows a list of all todos, and lets you POST to add new tasks'''
@api.doc('list_todos')
def get(self):
'''List all tasks'''
return "Get done!", 200
@api.doc('create_todo')
def post(self):
'''Create a new task'''
return "Post done!", 201
if __name__ == "__main__":
app.run()
If I execute above code with below curl command:
curl --location --request PUT 'http://127.0.0.1:5000/todos'
I get:
{"message":"The method is not allowed for the requested URL."}
Which is what I expect!
Code02
from flask import Flask, jsonify, request
from flask_restx import Resource, Api
app = Flask(__name__)
api = Api(
app, version='1.0', title='TodoMVC API',
description='A simple TodoMVC API',
)
ns = api.namespace('todos', description='TODO operations')
@app.errorhandler(404)
def page_not_found(e):
msg = f"The requested URL path {request.path} was not found on the server."
return jsonify(error=msg), 404
@app.errorhandler(405)
def method_not_allowed(e):
msg = f"The requested method '{request.method}' is not allowed."
return jsonify(error=msg), 405
@ns.route('/')
class RepositoryApi(Resource):
'''Shows a list of all todos, and lets you POST to add new tasks'''
@ns.doc('list_todos')
def get(self):
'''List all tasks'''
return "Get done!", 200
@ns.doc('create_todo')
def post(self):
'''Create a new task'''
return "Post done!", 201
if __name__ == "__main__":
app.run()
The only delta between Code01 and Code02 is the use of a namespace to implement the /todos path
when I execute Code02 and then run the same curl command I end up with a internal server error:
curl --location --request PUT 'http://127.0.0.1:5000/todos'
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
and it generates the below stack trace
Error Messages/Stack Trace
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [21/Jun/2020 19:49:52] "PUT /todos HTTP/1.1" 500 -
Error on request:
Traceback (most recent call last):
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask/app.py", line 1926, in dispatch_request
self.raise_routing_exception(req)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask/app.py", line 1908, in raise_routing_exception
raise request.routing_exception
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask/ctx.py", line 350, in match_request
result = self.url_adapter.match(return_rule=True)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/routing.py", line 1940, in match
raise MethodNotAllowed(valid_methods=list(have_match_for))
werkzeug.exceptions.MethodNotAllowed: 405 Method Not Allowed: The method is not allowed for the requested URL.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask_restx/api.py", line 599, in _should_use_fr_error_handler
adapter.match()
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/routing.py", line 1940, in match
raise MethodNotAllowed(valid_methods=list(have_match_for))
werkzeug.exceptions.MethodNotAllowed: 405 Method Not Allowed: The method is not allowed for the requested URL.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/routing.py", line 1873, in match
rv = rule.match(path, method)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/routing.py", line 911, in match
raise RequestPath(path)
werkzeug.routing.RequestPath: /todos/
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask_restx/api.py", line 634, in error_router
if self._has_fr_route():
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask_restx/api.py", line 614, in _has_fr_route
if self._should_use_fr_error_handler():
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask_restx/api.py", line 603, in _should_use_fr_error_handler
rule, _ = adapter.match(method=valid_route_method, return_rule=True)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/routing.py", line 1878, in match
query_args,
werkzeug.routing.RequestRedirect: 308 Permanent Redirect: None
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask_restx/api.py", line 599, in _should_use_fr_error_handler
adapter.match()
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/routing.py", line 1940, in match
raise MethodNotAllowed(valid_methods=list(have_match_for))
werkzeug.exceptions.MethodNotAllowed: 405 Method Not Allowed: The method is not allowed for the requested URL.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/routing.py", line 1873, in match
rv = rule.match(path, method)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/routing.py", line 911, in match
raise RequestPath(path)
werkzeug.routing.RequestPath: /todos/
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/serving.py", line 323, in run_wsgi
execute(self.server.app)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/serving.py", line 312, in execute
application_iter = app(environ, start_response)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask/app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask/app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask_restx/api.py", line 634, in error_router
if self._has_fr_route():
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask_restx/api.py", line 614, in _has_fr_route
if self._should_use_fr_error_handler():
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/flask_restx/api.py", line 603, in _should_use_fr_error_handler
rule, _ = adapter.match(method=valid_route_method, return_rule=True)
File "/Users/atselvan/workspace/code/py/pynxrm/venv/lib/python3.7/site-packages/werkzeug/routing.py", line 1878, in match
query_args,
werkzeug.routing.RequestRedirect: 308 Permanent Redirect: None
Environment
Python version: 3.7.3 pip packages: aniso8601==8.0.0 attrs==19.3.0 click==7.1.2 Flask==1.1.2 flask-restx==0.2.0 importlib-metadata==1.6.1 itsdangerous==1.1.0 Jinja2==2.11.2 jsonschema==3.2.0 MarkupSafe==1.1.1 pyrsistent==0.16.0 pytz==2020.1 six==1.15.0 Werkzeug==1.0.1 zipp==3.1.0
Regards, Allan Selvan
Hi, I'm also facing this issue. Here's the stack trace:
2020-12-24 05:49:37,644 - api.restplus - ERROR - 405 Method Not Allowed: The method is not allowed for the requested URL. Traceback (most recent call last): File "/usr/lib/python3.8/site-packages/flask/app.py", line 1950, in full_dispatch_request rv = self.dispatch_request() File "/usr/lib/python3.8/site-packages/flask/app.py", line 1926, in dispatch_request self.raise_routing_exception(req) File "/usr/lib/python3.8/site-packages/flask/app.py", line 1908, in raise_routing_exception raise request.routing_exception File "/usr/lib/python3.8/site-packages/flask/ctx.py", line 350, in match_request result = self.url_adapter.match(return_rule=True) File "/usr/lib/python3.8/site-packages/werkzeug/routing.py", line 1940, in match raise MethodNotAllowed(valid_methods=list(have_match_for)) werkzeug.exceptions.MethodNotAllowed: 405 Method Not Allowed: The method is not allowed for the requested URL. 2020-12-24 05:49:37,647 - app - ERROR - Exception on /health/datadump [GET] Traceback (most recent call last): File "/usr/lib/python3.8/site-packages/flask/app.py", line 1950, in full_dispatch_request rv = self.dispatch_request() File "/usr/lib/python3.8/site-packages/flask/app.py", line 1926, in dispatch_request self.raise_routing_exception(req) File "/usr/lib/python3.8/site-packages/flask/app.py", line 1908, in raise_routing_exception raise request.routing_exception File "/usr/lib/python3.8/site-packages/flask/ctx.py", line 350, in match_request result = self.url_adapter.match(return_rule=True) File "/usr/lib/python3.8/site-packages/werkzeug/routing.py", line 1940, in match raise MethodNotAllowed(valid_methods=list(have_match_for)) werkzeug.exceptions.MethodNotAllowed: 405 Method Not Allowed: The method is not allowed for the requested URL.
During handling of the above exception, another exception occurred:
Traceback (most recent call last): File "/usr/lib/python3.8/site-packages/flask/app.py", line 2447, in wsgi_app response = self.full_dispatch_request() File "/usr/lib/python3.8/site-packages/flask/app.py", line 1952, in full_dispatch_request rv = self.handle_user_exception(e) File "/usr/lib/python3.8/site-packages/flask_restx/api.py", line 638, in error_router return original_handler(f) File "/usr/lib/python3.8/site-packages/flask/app.py", line 1821, in handle_user_exception reraise(exc_type, exc_value, tb) File "/usr/lib/python3.8/site-packages/flask/_compat.py", line 39, in reraise raise value File "/usr/lib/python3.8/site-packages/flask_restx/api.py", line 636, in error_router return self.handle_error(e) File "/usr/lib/python3.8/site-packages/flask_restx/api.py", line 698, in handle_error default_data["message"] = default_data.get("message", str(e)) AttributeError: 'Response' object has no attribute 'get'
I had the same issue! Any news?
Faced the same issue. When using flask_restx with namespaces, what should return a 405 (Method Not Allowed) ends up returning a 500 (Internal Server Error) because of redirection within werkzeug and trailing slashes (or lack thereof) (triggering 308).
Turns out werkzeug has a strict_slashes
parameter you can use to circumvent the issue.
Rules that end with a slash are “branches”, others are “leaves”. If strict_slashes is enabled (the default), visiting a branch URL without a trailing slash will redirect to the URL with a slash appended.
Ref : https://werkzeug.palletsprojects.com/en/1.0.x/routing/
app = Flask(__name__)
app.url_map.strict_slashes = False
Adjusting this parameter changes the entire behavior of your application. Use with care.
I got the same error and solve with this impl: https://stackoverflow.com/a/57921890 the ExtendedAPI
allow to control the exception come from erkzeug.exceptions.MethodNotAllowed:
.
app = Flask(__name__)
app.url_map.strict_slashes = False```
is work it Turns out werkzeug has a strict_slashes parameter you can use to circumvent the issue.👍