I want to use Flask blueprints to organize my Flask-Restful resources into separate url prefixes. Regardless of what url prefix I set (during either blueprint creation or registration), everything gets mapped to the raw route paths. How do I correctly use Restful with blueprints?
app = Flask(__name__)
api = Api(app)
api.add_resource(Building, '/<int:id>', endpoint='building')
api.add_resource(Jack, '/<int:id>', endpoint='jack')
building_api = Blueprint('building_api', __name__)
jack_api = Blueprint('jack_api', __name__)
app.register_blueprint(building_api, url_prefix='/buildings')
app.register_blueprint(jack_api, url_prefix='/jacks')
All documentation I can find says that these should now be available at /buildings/<int:id> and /jacks/<int:id>, but both of those urls 404 and instead I can access the building one at /<int:id>. Hard coding the path in add_resource fixes it, but defeats the point of url_prefix.
You need to pass the blueprint to the Api instance, not the app.
building_bp = Blueprint('buildings', __name__)
building_api = Api(building_bp)
building_api.add_resource(Building, '/<int:id>')
app.register_blueprint(building_bp, url_prefix='/buildings')
This is zhe best way to do with blueprint:
from flask import Flask, Blueprint
from flask_restful import Api, Resource, url_for
app = Flask(__name__)
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
app.register_blueprint(api_bp)
you should send Blueprint'instance to Api
I do not know why but I struggled using the Blueprint as mentioned in the answers.
But here's a quick solution I found while going through the doc link. Making use of the prefix parameter in Api() does the job.
app = Flask(__name__)
api = Api(app, prefix='/buildings')
Now, all your routes will be prefixed with /buildings. Just make sure you use url_for('link') in places where you might have simply used a /link.
One more strange thing I noticed is that atleast for me, it did not work until I renamed my routes to the same name as their class names. For example, Class Home(Resource) should have a route to /home. Using /homeepage or any other route for Home Class causes an error. Not sure if it is only me.
Related
I'm new to Flask and the Blueprint concept. I understand the benefit of using Blueprint in a normal Flask application. However, after reading many posts/blogs/documentation, the benefit of using Blueprint with Flask-Restful is still unclear to me.
Let's consider two examples from the Flask-Restful documentation. The first one:
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/<string:id>')
api.add_resource(Bar, '/Bar', '/Bar/<string:id>')
api.add_resource(Baz, '/Baz', '/Baz/<string:id>')
We have 3 resources. We register them and start the project. Everything is clear at this point. I would be happy with this approach.
Then, they use blueprint:
from flask import Flask, Blueprint
from flask_restful import Api, Resource, url_for
app = Flask(__name__)
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
app.register_blueprint(api_bp)
As far as I can see, the code is getting more complicated:
More steps required: create the API instance with the blueprint, register the blueprint with the app,...
If I have another resource, e.g. user, I have to repeat all of those steps (please correct me if I'm wrong):
user_bp = Blueprint('user', __name__)
user_api = Api(user_bp)
user_api.add_resource(User, '/user/<int:id>')
app.register_blueprint(user_bp)
So, what is the benefit of using Blueprint here?
A blueprint in Flask is an object to structure a Flask application into subsets. This helps in organizing code and separating functionality.
For Flask-RESTful this can be used to create an application subset for your api. So for example you have a core blueprint, an auth blueprint and besides that an api blueprint. It can also be useful when you create a new version of your api that breaks backwards compatibility with the first version. In this case you can create a second blueprint for the new version.
You don’t have to create a new blueprint for each api endpoint that you create, you can reuse the api blueprint for each endpoint like:
from flask import Flask, Blueprint
from flask_restful import Api, Resource, url_for
app = Flask(__name__)
core_bp = Blueprint('core', __name__)
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
#core_bp.route('/')
def index():
return 'Index'
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
api.add_resource(User, '/user/<int:id>')
app.register_blueprint(core_bp)
app.register_blueprint(api_bp, url_prefix='/api')
Like this your core application is accessible via '/' and the api via '/api'.
I have a Flask app which has a Flask-RestPlus API as well as a "/" route. When I try to access "/" however, I get a 404. If I remove the Flask-RestPlus extension, the route works. How do I make both parts work together?
from flask import Flask
from flask_restplus import Api
app = Flask(__name__)
api = Api(app, doc="/doc/") # Removing this makes / work
#app.route("/")
def index():
return "foobar"
This is an open issue in Flask-RestPlus. As described in this comment on that issue, changing the order of the route and Api solves the issue.
from flask import Flask
from flask_restplus import Api
app = Flask(__name__)
#app.route("/")
def index():
return "foobar"
api = Api(app, doc="/doc/")
flask-restplus defines a different way of assigning routes according to their docs:
#api.route('/')
class Home(Resource):
def get(self):
return {'hello': 'world'}
Notice that the api variable is used instead of the app. Moreover, a class is used although I am not 100% sure it is required.
I'm trying to create a URL prefix for my web app's api. I want the api to return when I enter api.website.com/parameter.I am using Flask and Blueprint
api_bp = Blueprint('api', __name__,
template_folder='templates',
url_prefix='/api')
#api_bp.route("/")
def get_monkey_api():
address = request.args.get('address',
None)
if address and is_a_banano_address(address):
return monkey_api(banano_address)
else:
return render_template("NotABananoAddress.html"), 400
#api_bp.route("/<address>")
def monkey_api(address):
monKey = monkey_data_generator.generate_monKey(address)
if monKey.status is not 'Citizen':
return "API data on vanity monKeys does not exist"
return jsonify(monKey.serialize())
app = Flask(__name__)
app.register_blueprint(api_bp, url_prefix='/api')
Most of the code in unrelated. The fact is when I I am entering
api.website.com?address=xxx
or when I am entering
api.website.com/xxx
I should get my API as JSON back but I'm not. On localhost it doesn't return anything and doesn't show the prints that I even insert into the code and of course on Heroku it does not recognize the project when I using the prefix.
You gave your blueprint a URL prefix:
api_bp = Blueprint('api', __name__,
template_folder='templates',
url_prefix='/api')
and again with
app.register_blueprint(api_bp, url_prefix='/api')
That means you need to use hostname/api/ to get to get_monkey_api() view function, or hostname/api/xxxx to get to the monkey_api() view function.
Remove the URL prefixes if you want the routes to be found at the site root. If you want the blueprint to work for a separate subdomain, then use the subdomain='api' option, not a URL prefix.
Note that for subdomains to work, you need to configure the SERVER_NAME config option so that subdomains can be detected. If you want to test this locally, edit your /etc/hosts file to add some development aliases that point to your server, then set SERVER_NAME to match.
Is there a way to get the routes defined in a blueprint? I know this (http://flask.pocoo.org/snippets/117/) snippit exists, but requires to have the app initalized to use url_map. Is there a way to view the routes without an application? I'm developing an api with flask-restful and I would like to display the routes from within the blueprint without the app to keep it self contained.
Using the information provided by polyfunc, I was able to come up with this solution:
from flask import Blueprint, current_app, url_for
from flask_restful import Resource, Api
api_blueprint = Blueprint('api', __name__)
api = Api(api_blueprint)
#api.resource('/foo')
class Foo(Resource):
def get(self):
prefix = api_blueprint.name + '.' # registered classes will have this as their prefix
# Get current rules
rules = current_app.url_map.iter_rules()
# Get list from routes registered under the blueprint
routes = [url_for(rule.endpoint) for rule in rules if rule.endpoint.startswith(prefix)]
I know when flask builds large application, it has registered multiple blueprints.
The flask blueprint starts to initial a blueprint object, it has declared name of first layer of endpoint in the same time.
For example:
users_bp = Blueprint('users', __name__)
According to the expression, the name of first layer of endpoint of users_bp is users.
The blueprint object continues to register its view function, it has declared name of second layer of endpoint in the same time.
#users_bp.route('/login')
def login():
# do something
According to the expression, the name of second layer of endpoint of users_bp is login, it's from view name.
If I want to use endpoint to get corresponding url, I should be to do : url_for('users.login').
So it's workflow of building large application from flask tutorial. Is it right?
Let's get back on point. Is it possible to build three layers of endpoint as url_for('api. users.login')?
How do I package the blueprint or flask app to complete my wanted structure? Is it available?
You can set an endpoint within your route decorator, for example:
from flask import Flask, render_template_string
app = Flask(__name__)
#app.route('/', endpoint="this.is.the.home.endpoint")
def index():
_html="<a href='{{url_for('this.is.another.endpoint')}}'>Go to another endpoint</a>"
return render_template_string(_html)
#app.route('/another', endpoint="this.is.another.endpoint")
def another():
_html="<a href='{{url_for('this.is.the.home.endpoint')}}'>Go to the home page</a>"
return render_template_string(_html)
if __name__ == '__main__':
app.run()