Search code examples
pythonflaskflask-restful

Catch-All URL example in flask-restful also catching /


There is a catch-all URL example for Flask:

from flask import Flask
app = Flask(__name__)

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
    return 'You want path: %s' % path

if __name__ == '__main__':
    app.run()

Decorators can be translated to the following to code look more similar to Flask-RESTful achieving the same functionality:

app.add_url_rule('/', 'catch_all', catch_all, defaults={'path': ''})
app.add_url_rule('/<path:path>', 'catch_all', catch_all, defaults={'path': ''})

If I'm right, this can be further translated to an equivalent Flask-RESTful app (at least debuging shows it creates the same URL routes):

class RESTapp(Resource):
    def get(self, path):
        # do get something

api.add_resource(RESTapp, '/', '/<path:path>', defaults={'path': ''})

The problem is that this app redirects all URLs to / and I can not get the requested path in get() function. I want to handle all paths ( / and '/') in the same function as in Flask, but using Flask-RESTful.

Similar questions:

  • Catch-All URL in flask-restful The Asker does not want to catch / or at least not in the same functions as other URL-s.
  • Flask restful API urls The Answerer proposes two classess as two resources. I have to initialize the class through resource_class_kwargs keyword argument and I want to keep only one instance, so it will not be good for me.

What I've tried:

  • Create two add_resource calls for the same class. It end with error.
  • Debug add_resource. It shows that it creates a resource view function from the Endpoint and that is given to the add_url_rule function. Else it works the same as the two subsequent add_url_rule functions.

Solution

  • By trial and error I've figured out the solution, which is neither documented nor looks like to the expected way of doing it (simmilarly as in Flask, showed in the question).

    One must supply a Pythonic default argument to get() and other functions: get(stuff='DEF_VAL')

    Full example which is working:

    from flask import Flask
    from flask_restful import Api, Resource
    
    app = Flask(__name__)
    api = Api(app)
    
    class RESTapp(Resource):
    
        @staticmethod
        def get(path=''):  # <-- You should provide the default here not in api.add_resource()!
            return 'You want path: \'%s\'' % path  # do get something
    
    
    api.add_resource(RESTapp, '/', '/<path:path>')  # Here just the URLs must be the arguments!
    
    
    if __name__ == '__main__':
        app.run()