Search code examples
pythonflaskpython-importflask-restful

How to access api.url_for in big Flask-Restful API


I'm working on a Restful API using Flask-Restful with more resources than I'd like to keep in my app.py. So I've applied the suggested project structure. Now I'd like to access api.url_for() from a resource to generate some links, but it seems I'd have to from app import api to do that.

To avoid circular imports, my current solution is to do a lazy import. But there has be a better way, right?

app.py:

from flask import Flask
from flask_restful import Api
from myapi.resources.foo import Foo
from myapi.resources.bar import Bar
from myapi.resources.baz import Baz

app = Flask(__name__)
api = Api(app)

api.add_resource(Foo, '/Foo', '/Foo/<str:id>')
api.add_resource(Bar, '/Bar', '/Bar/<str:id>')
api.add_resource(Baz, '/Baz', '/Baz/<str:id>')

resource/foo.py (bar.py respectively):

from flask_restful import Resource
from bar import Bar

class Foo(Resource):
    def get(self):
        from app import api
        related = api.url_for(Bar, foo=self.id)
        return {'Foo':self.id, 'related_bar':related}, 200

    def post(self):
        pass

Solution

  • You can move your imports down, to below the api = Api(app) line:

    from flask import Flask
    from flask_restful import Api
    
    app = Flask(__name__)
    api = Api(app)
    
    from myapi.resources.foo import Foo
    from myapi.resources.bar import Bar
    from myapi.resources.baz import Baz
    
    api.add_resource(Foo, '/Foo', '/Foo/<str:id>')
    api.add_resource(Bar, '/Bar', '/Bar/<str:id>')
    api.add_resource(Baz, '/Baz', '/Baz/<str:id>')
    

    Now the api name has been defined and you can safely import from app import api in your resources modules:

    from flask_restful import Resource
    from app import api
    from bar import Bar
    
    class Foo(Resource):
        def get(self):
            related = api.url_for(Bar, foo=self.id)
            return {'Foo':self.id, 'related_bar':related}, 200
    
        def post(self):
            pass
    

    See the Larger Applications pattern in the Flask documentation.