flask-rest-jsonapi: Unable to add blueprints without errors
I don’t know if this is an issue or just my ignorance but I am having difficulty adding my api routes with a blue print prefix:
app/api/views:
from app.api.resources import UserList, UserDetail, MaterialList, MaterialDetail
from flask import Blueprint
from flask_rest_jsonapi import Api
json_api = Blueprint('api', __name__, url_prefix='/api') # @todo figure out how to add blueprints
api = Api(blueprint=json_api)
# User routes
api.route(UserList, 'user_list', '/users')
api.route(UserDetail, 'user_detail', '/users/<string:id>')
# Material routes
api.route(MaterialList, 'material_list', '/materials')
api.route(MaterialDetail, 'material_detail', '/materials/<string:id>')
app/init.py
# -*- coding: utf-8 -*-
from flask import Flask
from app.api.views import api
from app.database import db
from app.cors import cors
from app.auth.views import auth
def create_app():
app = Flask(__name__)
app.config.from_object('config')
db.init_app(app)
cors.init_app(app)
api.init_app(app)
app.register_blueprint(auth)
return app
def setup_database(app):
with app.app_context():
db.create_all()
app = create_app()
setup_database(app)
Now if I visit http://localhost:5000/api/materials I receive the following error:
werkzeug.routing.BuildError: Could not build url for endpoint ‘material_list’. Did you mean ‘api.material_list’ instead?
The obvious solution that springs to mind would be to change the endpoint name in routes and schemas to: api.material_list
however the error is now:
werkzeug.routing.BuildError: Could not build url for endpoint ‘api.material_list’. Did you mean ‘api.api.material_list’ instead?
If I remove the blueprint:
api = Api()
and visit: http://localhost:5000/materials everything works perfectly!
I’ve tried defining the blueprint in every way conceivable but I’m still getting the same error. If this is not an issue and I’m just being a noob please forgive me.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 1
- Comments: 18
I have seen in your skeleton app that your schemas are not setup correctly. If you want to use a blueprint like that
Blueprint('api', __name__, url_prefix='/api')
you must add the api prefix to all your endpoints in your schemas. Soself_view = 'person_detail'
becomesself_view = 'api.person_detail'
. First update your schemas and tell me if it fix the issue. Note that I’m talking about about the api prefix, the first parameter of your blueprint not the url prefix. For example:Blueprint('api_prefix', __name__, url_prefix='/api')
your schema must looks like thisself_view = 'api_prefix.person_detail'
.Just share the exception that is being thrown, may be I will be able you help you better.
Now when you are declaring schemas everywhere for view_name, prefix with
api.
.Similarly in relationships too, but not while declaring routes.
Then I guess there would be no problem. If you are still seeing 404s then try by not passing the app while declaring the api extension and instead after declaring all the routes, do init_app.
I don’t know why this happens, but after doing some hit and trials after a full revamp of my code, I discovered this was the problem for which I spent quite some time before I figured it out by myself.
If you need any guidance for project structure, this is what I am following at present after several rounds of rework:
If you don’t have groups you can also declare models and schemas as modules instead of packages. This structure reduces cyclic dependencies all together (the thing that bugged me a lot), since model declarations doesn’t require other models or schemas or resources. Same goes with schema declaration. But resources that need both, can use them independently and no one resource depends on other resource, no issues of cyclic dependency at all.
What I further suggest is to make a helper class Endpoint as utils. Declaring routes like
api.route
will become a lot tiring process and it will anyways look ugly at end. Try to make your routes look like a dictionary or mapping of views to resource and routes (better readability). Then finally import all such endpoint mappings and declare your routes together under a loop.This is a very common use case, I figured it out from the issue above. An example would be good in the docs.