code:
blueprint:
from flask import Blueprint
from flask_restful import Api
################################
### Local Imports ###
################################
profile_api = Blueprint('profile_api', __name__)
api = Api(profile_api)
from .views import *
views:
class ShowProfPic(Resource):
def get(self):
return "hey"
api.add_resource(ShowProfPic, '/get profile picture/',endpoint="showpic")
how do we do a url_for with flask_restful?
because when I do.
url_for('showpic') it's a routing error
and when I do url_for('api.ShowProfPic')
it's also still a routing error
I've got the answer.
Apparently when working with blueprints
the way to access flask_restful's url_for is
url_for('blueprint_name.endpoint)
meaning an endpoint has to be specified on the resource
so using the example above:
profile_api = Blueprint('profile_api', __name__)
api = Api(profile_api)
from .views import *
class ShowProfPic(Resource):
def get(self):
return "hey"
api.add_resource(ShowProfPic, '/get profile picture/',endpoint="showpic")
to reference the ShowProfPic class and get it's endpoint
it's url_for('blueprint_name.endpoint')
so that's url_for(profile_api.showpic)
Related
code:
blueprint:
from flask import Blueprint
from flask_restful import Api
################################
### Local Imports ###
################################
profile_api = Blueprint('profile_api', __name__)
api = Api(profile_api)
from .views import *
views:
class ShowProfPic(Resource):
def get(self):
return "hey"
api.add_resource(ShowProfPic, '/get profile picture/',endpoint="showpic")
how do we do a url_for with flask_restful?
because when I do.
url_for('showpic') it's a routing error
and when I do url_for('api.ShowProfPic')
it's also still a routing error
I've got the answer.
Apparently when working with blueprints
the way to access flask_restful's url_for is
url_for('blueprint_name.endpoint)
meaning an endpoint has to be specified on the resource
so using the example above:
profile_api = Blueprint('profile_api', __name__)
api = Api(profile_api)
from .views import *
class ShowProfPic(Resource):
def get(self):
return "hey"
api.add_resource(ShowProfPic, '/get profile picture/',endpoint="showpic")
to reference the ShowProfPic class and get it's endpoint
it's url_for('blueprint_name.endpoint')
so that's url_for(profile_api.showpic)
I've been following some tutorials(basic examples), trying to create a RESTful API with Flask-Restx. However, when I try to register endpoints with a more complex project structure(following this example), no API endpoints get registered.
I defined the namespace of an endpoint and tried to register that in app.py:
from flask import Flask, Blueprint, url_for, jsonify
from flask_login import LoginManager
import settings
from database import db
from BE.api.__init__ import api
from BE.api.endpoints.images import ns as image_api
from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
#flask_restx API supports prior flask_restplus api
def configure_app(app):
app.config['SWAGGER_UI_DOC_EXPANSION'] = settings.RESTPLUS_SWAGGER_EXPANSION
app.config['RESTPLUS_VALIDATE'] = settings.RESTPLUS_VAL
app.config['RESTPLUS_MASK_SWAGGER'] = settings.RESTPLUS_MASK_SWAGGER
app.config['SQLALCHEMY_DATABASE_URI'] = settings.SQLALCHEMY_DATABASE_URI
app.config['UPLOAD_FOLDER'] = settings.UPLOAD_FOLDER
app.config['MAX_UPLOAD_LENGTH'] = 24 * 1024 * 1024 # limits filesize to 24 mb
def init_app(app):
configure_app(app)
api.add_namespace(image_api)
app.register_blueprint(api, url_prefix='/api/1')
api.init_app(app)
db.init_app(app)
[....main etc]
The API init.py looks as follows:
from flask_restx import Api
api = Api(version='0.1', title='Backend API', description='Backend API for sticker generation')
and the endpoint I want to register:
from flask import request, flash, Blueprint, redirect, send_file
from flask_restx import Resource, Namespace
from BE.database import db as database
from BE.database.models import Image as dbImage
from BE.api.api_definition import image
[....]
ns = Namespace('image', path='/image', description='Available Ops')
#ns.route('/test')
class TestClass(Resource):
def get(self):
return "Hello World"
[....]
While #app.route('/') works in app.py, the #ns.route('/') remains unsuccessful and I'm at a loss as to why.
Answering my own question:
Turns out that running app.py from PyCharm does not run via main() or was configured in a wrong way, but rather appears to just launch the Flask server from the initial app = Flask(__name__). Therefore configure_app() or init_app() never get called.
Transforming the project layout to something more closely resembling Flask's intended layout resolves that in part, resulting in the intended endpoints to work.
I have a flask application and I'm trying to use flask-restplus and blueprints. Unfortunately my api endpoint always returns The requested URL was not found on the server. even though I can see that it exists in the output of app.url_map.
The project is laid out as follows:
- app.py
- api
- __init__.py
- resources.py
app.py
from api import api, api_blueprint
from api.resources import EventListResource, EventResource
app = Flask(__name__)
app.register_blueprint(api_blueprint)
db.init_app(flask_app)
app.run()
api/__init__.py
from flask_restplus import Api
from flask import Blueprint
api_blueprint = Blueprint("api_blueprint", __name__, url_prefix='/api')
api = Api(api_blueprint)
api/resources.py
from flask_restplus import Resource
from flask import Blueprint
from . import api, api_blueprint
#api_blueprint.route('/events')
class EventListResource(Resource):
def get(self):
"stuff"
return items
def post(self):
"stuff"
db.session.commit()
return event, 201
The application starts without issue and I can see that '/api/events' appears in app.url_map so I'm not really sure why the url can't be found. Any help appreciated, thanks!
Flask-RESTPlus provides a way to use almost the same pattern as Flaskās blueprint. The main idea is to split your app into reusable namespaces.
You can do it this way:
app.py
from flask_restplus import Api
from api import api_namespace
app = Flask(__name__)
api = Api(app)
db.init_app(flask_app)
from api import api_namespace
api.add_namespace(api_namespace, path='/api')
app.run()
api/init.py
from flask_restplus import Namespace
api_namespace = Namespace('api_namespace')
api/resources.py
from flask_restplus import Resource
from api import api_namespace
#api_namespace.route('/events')
class EventListResource(Resource):
def get(self):
"stuff"
return items
def post(self):
"stuff"
db.session.commit()
Here is the link to documentation:
https://flask-restplus.readthedocs.io/en/stable/scaling.html
I am running unittests in a Flask app and I keep getting 404 when views.py file is not imported even though it is not used. I have such tests.py package:
import unittest
from presence_analyzer import main, utils
from presence_analyzer import views
class PresenceAnalyzerViewsTestCase(unittest.TestCase):
def setUp(self):
self.client = main.app.test_client()
def test_mainpage(self):
resp = self.client.get('/')
self.assertEqual(resp.status_code, 302)
When I delete views import the described problem occurs. Views are organized in a similar way to this:
from presence_analyzer.main import app
#app.route('/')
def mainpage():
return redirect('/static/presence_weekday.html')
And the main.py file:
import os.path
from flask import Flask
app = Flask(__name__) # pylint: disable=invalid-name
app.config.update(
DEBUG=True,
)
I guess it's something similar to what happened in this case, so I'm trying to change the application so that I don't have to make this dumb imports while testing. I've been trying to make use of the answer from above, but still can't make it work and these docs don't seem helpful. What am I doing wrong? main.py:
from flask.blueprints import Blueprint
PROJECT_NAME = 'presence_analyzer'
blue_print = Blueprint(PROJECT_NAME, __name__)
def create_app():
app_to_create = Flask(__name__) # pylint: disable=invalid-name
app_to_create.register_blueprint(blue_print)
return app_to_create
app = create_app()
views.py:
from presence_analyzer.main import app, blue_print
#blue_print.route('/')
def mainpage():
return redirect('/static/presence_weekday.html')
And tests.py has remained unchanged.
You must import views, or the route will not be registered. No, you are not executing the views directly, but importing executes code all module-level code. Executing code calls route. route registers the view function. You cannot get around needing to import a module in order to use the module.
I am adding Swagger UI to my Python Flask application using Flasgger. Most common examples on the Internet are for the basic Flask style using #app.route:
from flasgger.utils import swag_from
#app.route('/api/<string:username>')
#swag_from('path/to/external_file.yml')
def get(username):
return jsonify({'username': username})
That works.
In my application however, I am not using #app.route decorators to define the endpoints. I am using flask Blueprints. Like following:
from flask import Flask, Blueprint
from flask_restful import Api, Resource
from flasgger.utils import swag_from
...
class TestResourceClass(Resource):
#swag_from('docs_test_get.yml', endpoint='test')
def get() :
print "This is the get method for GET /1.0/myapi/test endpoint"
app = Flask(__name__)
my_api_blueprint = Blueprint('my_api', __name__)
my_api = Api(my_api_blueprint)
app.register_blueprint(my_api_blueprint, url_prefix='/1.0/myapi/')
my_api.add_resource(TestResourceClass, '/test/'
endpoint='test',
methods=['GET', 'POST', 'PUT', 'PATCH', 'DELETE'])
....
As seen above, I used #swag_from decorator on the TestResourceClass.get() method which is bound to the GET method endpoint. I also have the endpoint=test matching in the two places.
But I am not getting anything on the Swagger UI, it is all blank. The docs_test_get.yml file does contain the valid yaml markup to define the swagger spec.
What am I missing? How can I get Flasgger Swagger UI working with Flask Blueprint based setup?
Now there is an example of blueprint app in https://github.com/rochacbruno/flasgger/blob/master/examples/example_blueprint.py
"""
A test to ensure routes from Blueprints are swagged as expected.
"""
from flask import Blueprint, Flask, jsonify
from flasgger import Swagger
from flasgger.utils import swag_from
app = Flask(__name__)
example_blueprint = Blueprint("example_blueprint", __name__)
#example_blueprint.route('/usernames/<username>', methods=['GET', 'POST'])
#swag_from('username_specs.yml', methods=['GET'])
#swag_from('username_specs.yml', methods=['POST'])
def usernames(username):
return jsonify({'username': username})
#example_blueprint.route('/usernames2/<username>', methods=['GET', 'POST'])
def usernames2(username):
"""
This is the summary defined in yaml file
First line is the summary
All following lines until the hyphens is added to description
the format of the first lines until 3 hyphens will be not yaml compliant
but everything below the 3 hyphens should be.
---
tags:
- users
parameters:
- in: path
name: username
type: string
required: true
responses:
200:
description: A single user item
schema:
id: rec_username
properties:
username:
type: string
description: The name of the user
default: 'steve-harris'
"""
return jsonify({'username': username})
app.register_blueprint(example_blueprint)
swag = Swagger(app)
if __name__ == "__main__":
app.run(debug=True)
You just need to add your blueprint's name when you reference endpoint. Blueprints create namespaces. Example below. And useful tip: use app.logger.info(url_for('hello1')) for debugging problems with endpoint - it shows very useful error messages like this Could not build url for endpoint 'hello1'. Did you mean 'api_bp.hello1' instead?.
from flask import Flask, Blueprint, url_for
from flask_restful import Api, Resource
from flasgger import Swagger, swag_from
app = Flask(__name__)
api_blueprint = Blueprint('api_bp', __name__)
api = Api(api_blueprint)
class Hello(Resource):
#swag_from('hello1.yml', endpoint='api_bp.hello1')
#swag_from('hello2.yml', endpoint='api_bp.hello2')
def get(self, user=''):
name = user or 'stranger'
resp = {'message': 'Hello %s!' % name}
return resp
api.add_resource(Hello, '/hello', endpoint='hello1')
api.add_resource(Hello, '/hello/<string:user>', endpoint='hello2')
app.register_blueprint(api_blueprint)
swagger = Swagger(app)
app.run(debug=True)
swag_from function have some error to parse file path.you can use doc string to define api in get() first.
flasgger will parse MethodView() method like get,post.
Seems flasgger does not work or has no proper support for blue print style Flask definitions (yet). I used https://github.com/rantav/flask-restful-swagger which worked great!