I'm working on an API using flask. I had the code for running the app so:
def create_app():
"""Create Flask app."""
app = Flask(__name__)
# accepts both /endpoint and /endpoint/ as valid URLs
app.url_map.strict_slashes = False
# register each active blueprint
for url, blueprint in ACTIVE_ENDPOINTS:
app.register_blueprint(blueprint, url_prefix=url)
return app
So, I started to do a documentation using Flask Swagger UI, I created a static directory and into create a swagger.json file with the template. For the implementation I added this:
def create_app():
"""Create Flask app."""
app = Flask(__name__)
# accepts both /endpoint and /endpoint/ as valid URLs
app.url_map.strict_slashes = False
# register each active blueprint
for url, blueprint in ACTIVE_ENDPOINTS:
app.register_blueprint(blueprint, url_prefix=url)
# swagger configs
SWAGGER_URL = "/swagger"
API_URL = "/static/swagger.json"
SWAGGER_BLUEPRINT = get_swaggerui_blueprint(
SWAGGER_URL,
API_URL,
config={
"app_name": "iam-challenge-juanda"
}
)
app.register_blueprint(SWAGGER_BLUEPRINT, url_prefix=SWAGGER_URL)
#app.route("/static/swagger.json")
def specs():
return send_from_directory(os.getcwd(), "swagger.json")
return app
When I run de app in localhost just received: Failed to load API definition - Fetch error
NOT FOUND /static/swagger.json
Any idea why? I think so using a correct url for swagger.json file
Related
I'm a beginner in Python and flask. I am going through the Flask tutorial up to Blog Blueprint section.
I would like to know the meaning of app = ...
int the following code:
def create_app():
app = ...
# existing code omitted
from . import blog
app.register_blueprint(blog.bp)
app.add_url_rule('/', endpoint='index')
return app
In a real Flask application ... would be replaced by a call to the Flask constructor, with the desired configurations.
Check this example on how to initialize a Flask app: https://flask.palletsprojects.com/en/2.1.x/tutorial/factory/
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
#app.route('/hello')
def hello():
return 'Hello, World!'
return app
I have created a small Flask application which stores its data in an sqlite database that I access via flask-sqlalchemy.
However, when I run it, I get the following error:
RuntimeError: No application found. Either work inside a view function or push an application context. See http://flask-sqlalchemy.pocoo.org/contexts/.
I have debugged my application and now know that this error stems from these two functions:
def user_exists(email):
if User.query.filter_by(email = email).count() == 0:
return False
else:
return True
def get_user(email):
user = User.query.filter_by(email = email).first()
return user
Now I am wondering: Is it impossible to access the database via flask-sqlalchemy outside of view functions?
For further context, I added the files in which I configure my flask app:
presentio.py
from app import create_app
app = create_app(os.getenv("FLASK_CONFIG", "default"))
app/init.py
from flask_mail import Mail
from flask_sqlalchemy import SQLAlchemy
from config import config
mail = Mail()
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
mail.init_app(app)
db.init_app(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix = "/auth")
from .text import text as text_blueprint
app.register_blueprint(text_blueprint, url_prefix = "/text")
return app
You need to give the flask app a context after you create it.
This is done automatically in view functions, but outside those, you need to do this after you create the app:
app.app_context().push()
See the docs: https://flask-sqlalchemy.palletsprojects.com/en/2.x/contexts/
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 have a flask MethodView as follows
class Ping(MethodView):
"""
Ping point implementation
"""
def get(self) -> Response:
"""
Checks the server's health
:return: a json as status = 200
"""
return jsonify(status=200)
I want to add Access-Control-Allow-Origin for this end-point.
def create_app() -> Flask:
"""
Creates the flask application.
:return: returns an app instance.
"""
app: Flask = Flask(__name__, instance_relative_config=True)
# db config
app.config["db"] = os.environ.get("APP_DB_NAME")
app.config["host"] = os.environ.get("APP_DB_HOST")
app.config["password"] = os.environ.get("APP_DB_PASSWORD")
app.config["port"] = os.environ.get("APP_DB_PORT")
app.config["user"] = os.environ.get("APP_DB_USER")
# secret key config
app.config.from_mapping(SECRET_KEY=os.environ.get("SECRET"))
add_urls(app)
return app
def add_urls(app: Flask) -> None:
"""
Add urls to app
:param app: Flask app instance
"""
# TODO: Declare end-points in a dictionary and iterate.
app.add_url_rule(
f"{END_POINT}/ping", view_func=Ping.as_view("ping")
)
The return jsonify() method does not have a way to pass headers. How to set header 'Access-Control-Allow-Origin' ?
Install the Flask-Cors package
And import it as:-
from flask_cors import CORS
In create_app() method, after you initializes Flask application that is,
app: Flask = Flask(__name__, instance_relative_config=True)
Declare this line -> CORS(app)
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!