404 when accessing resource Flask-Restful - python

from flask import g, request, session, render_template, flash, redirect, url_for
from flask import current_app as app
#app.route('/')
def home():
return 'this works'
from flask_restful import Resource, Api
from app.extensions import api
class HelloWorld(Resource):
def get(self):
return {'Hello': 'World'}
api.add_resource(HelloWorld, '/test') # Getting a 404 for this route on http://127.0.0.1:5000/test
Extensions sets up the api variable:
api = Api()
api.init_app(app)
I cannot figure out why I get a 404 when trying to access an api resource?

Ok, the problem seems to be that the below ordering is wrong. I must add resources before I init the api.
api = Api()
api.init_app(app)
api.add_resource(HelloWorld, '/')
Fix:
api = Api()
api.add_resource(HelloWorld, '/')
api.init_app(app)
This is quite strange given that e.g. SQLAlchemy needs to call init_app before it is used...

Related

What is the benefit of using Blueprint in Flask-Restful?

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'.

Requesting a resource results in a 404 (Flask)

As I'm testing the URL endpoint for a resource, I'm getting a 404 Not Found error. I don't understand why it cannot be found as the resource is added to the api instance and the blueprint is added to the flask app.
tests.py
def test_todo_collection_resource(self):
with app.test_client() as client:
http_response = client.get("/todos/")
json_data = http_response.get_json()
self.assertEqual(http_response.status_code, 200) <<<---FAILS
self.assertTrue(http_response.is_json)
self.assertTrue(all(
(instance['name'] in self.todo_resources.values()
for instance in json_data)
))
todos.py
from flask import Blueprint, jsonify
from flask_restful import Api, Resource, fields, marshal
from models import Todo
todo_api = Blueprint("resources.todos", __name__)
api = Api(todo_api)
todos_fields = {
'name': fields.String
}
class TodoList(Resource):
pass
api.add_resource(
TodoList,
''
'todos'
)
app.py
from flask import Flask, g, jsonify, render_template
from config import HOST, PORT, DEBUG
from peewee import *
import models
from resources.todos import todo_api
app = Flask(__name__)
app.register_blueprint(todo_api, url_prefix="/todos/")
models.DATABASE.init('todo_api.db')
models.initialize(models.User, models.Todo)
#app.route('/')
def my_todos():
return render_template('index.html')
if __name__ == '__main__':
app.run(host=HOST, port=PORT, debug=DEBUG)
You have not defined any methods in your TodoList class that is why there is a 404 error as it can't find any HTTP methods defined on that endpoint. The Flask-RESTful documentation specifies defining HTTP methods in your Resource class e.g.
class TodoList(Resource):
def get(self):
return TODOS

Registering multiple restplus blueprints on same prefix doesn't work

So I'm building an API with Flask-RestPlus and using blueprints to divide the code into smaller chunks, but when trying to register multiple API endpoint, providing same URL prefix, only one blueprint registers.
Blueprint Templates:
from flask import Blueprint
from flask_restplus import Api, Resource
tmpl_bp = Blueprint('templates_api', __name__)
api = Api(tmpl_bp)
ns_tmpl = api.namespace('templates', description='Templates operations')
#ns_tmpl.route('/')
class Templates(Resource):
def get(self):
return "All templates"
def post(self):
return "Added/updated template"
Blueprint Render:
from flask import Blueprint
from flask_restplus import Api, Resource
rend_bp = Blueprint('render_api', __name__)
api = Api(rend_bp)
ns_render = api.namespace('render', description='Render actions')
#ns_render.route('/')
class Render(Resource):
def post(self):
return "Rendering everything"
The main app code, where registering happens:
from flask import Flask, render_template
from api.templates import tmpl_bp
from api.render import rend_bp
app = Flask(__name__)
app.register_blueprint(tmpl_bp, url_prefix="/api/v1")
app.register_blueprint(rend_bp, url_prefix="/api/v1")
#app.route('/')
def home():
return "This is the main page"
The resulting Swagger API:
I was expecting both the Templates and the Render blueprints to be served on /api/v1/ as /api/v1/templates and /api/v1/render respectively. But only one registers every time.
How do I get both blueprints served under the same prefix?
You don't need to use Blueprint, it's enough to use flask_restplus Namespaces.
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.
from flask import Flask, render_template
from flask_restplus import Resource, Api
from api.templates import tmpl_bp
from api.render import rend_bp
app = Flask(__name__)
api = Api(app)
api.add_namespace(tmpl_bp, path="/api/v1/templates")
api.add_namespace(rend_bp, path="/api/v1/render")
#api.route('/')
def home():
return "This is the main page"
You can find out more details here https://flask-restplus.readthedocs.io/en/stable/scaling.html

Flask route at / returns 404 when used with Flask-Restplus

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.

Python 3 Flask Rest API Get multiple argument

How to have get rest api on python with multiple arguments? I tested my rest api on IE by the below url
http://127.0.0.1:5002/search_np?item=testing&posn=1
from flask import Flask, request
from flask_restful import Resource, Api
from flask_cors import CORS
....
app = Flask(__name__)
cors = CORS(app, resources={r"*": {"origins": "*"}})
api = Api(app)
api.add_resource(search_nextpage, '/search_np')
....
class search_nextpage(Resource):
def get(self):
search_item = request.args.get('item', "")
search_posn =request.args.get('posn', "")
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class search_nextpage(Resource):
def get(self):
item = request.args.get('item')
posn = request.args.get('posn')
return {'item': item, 'posn': posn}
api.add_resource(search_nextpage, '/search_np')
if __name__ == '__main__':
app.run(debug=True)
Requesting http://127.0.0.1:5000/search_np?item=chocolate&posn=0 yields the following output.
{
"item": "chocolate",
"posn": "0"
}
The arguments item and posn are retrieved from the querystring and returned in a json dictionary.

Categories