'Flask Server API using classes starts causing problems with nested URIs (werkzeug.routing.BuildError)

Today I bring you a new question due to my inexperience, eagerness to learn and desire for my project to work.

I have created a Flask server that will serve as my API (I know it's a horrible decision from what I've read, but let me learn strange moves).

from flask import Flask
from flask_cors import CORS
from flask_restful import Api

app = Flask(__name__)
api = Api(app)
CORS(app)

from classes.CommentAPI import CommentAPI
api.add_resource(CommentAPI, '/comments/<int:id>', endpoint='comment')

from classes.CommentListAPI import CommentListAPI
api.add_resource(CommentListAPI, '/comments', endpoint='comments')

from classes.FollowerAPI import FollowerAPI
api.add_resource(FollowerAPI, '/followers/<int:id>', endpoint='follower')

[...]


from classes.Groups.GroupAPI import GroupAPI
api.add_resource(GroupAPI, '/groups/<int:id>', endpoint='group')

from classes.Groups.GroupListAPI import GroupListAPI
api.add_resource(GroupListAPI, '/groups', endpoint='groups')

from classes.Groups.GroupCommentAPI import GroupCommentAPI
api.add_resource(GroupCommentAPI, '/groups/<int:group_id>/comments/<int:id>', endpoint='group_comment')

from classes.Groups.GroupCommentListAPI import GroupCommentListAPI
api.add_resource(GroupCommentListAPI, '/groups/<int:id>/comments', endpoint='group_comments')

from classes.Groups.GroupLikeAPI import GroupLikeAPI
api.add_resource(GroupLikeAPI, '/groups/<int:group_id>/likes/<int:id>', endpoint='group_like')

from classes.Groups.GroupLikeListAPI import GroupLikeListAPI
api.add_resource(GroupLikeListAPI, '/groups/<int:id>/likes', endpoint='group_likes')

from classes.Groups.GroupMemberAPI import GroupMemberAPI
api.add_resource(GroupMemberAPI, '/groups/<int:group_id>/members/<int:id>', endpoint='group_member')

[...]

All API calls to non-group URIs work fine. The problem with the group functions is that it seems that the logic of the classes that I have created is not working well.

The error that pops up when I make a call like this:

http://<SERVER>/groups/1/comments/1

It is the following:

[2022-05-03 22:47:23,007] ERROR in app: Exception on /groups/1/comments/1 [GET]
Traceback (most recent call last):
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/flask/app.py", line 1523, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/flask/app.py", line 1509, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/flask_restful/__init__.py", line 467, in wrapper
    resp = resource(*args, **kwargs)
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/flask/views.py", line 84, in view
    return current_app.ensure_sync(self.dispatch_request)(*args, **kwargs)
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/flask_restful/__init__.py", line 582, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/home/lorty/Escritorio/proyectos/espaCy_API/classes/Groups/GroupCommentAPI.py", line 18, in get
    return {'group_comment': marshal(group_comment[0], group_comment_fields)}
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/flask_restful/__init__.py", line 635, in marshal
    return OrderedDict([(envelope, OrderedDict(items))]) if envelope else OrderedDict(items)
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/flask_restful/__init__.py", line 633, in <genexpr>
    else make(v).output(k, data))
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/flask_restful/fields.py", line 304, in output
    o = urlparse(url_for(endpoint, _external=self.absolute, **data))
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/flask/helpers.py", line 336, in url_for
    return appctx.app.handle_url_build_error(error, endpoint, values)
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/flask/helpers.py", line 323, in url_for
    rv = url_adapter.build(
  File "/home/lorty/Escritorio/proyectos/espaCy_API/venv/lib/python3.9/site-packages/werkzeug/routing.py", line 2305, in build

raise BuildError(endpoint, values, method, self) werkzeug.routing.BuildError: Could not build url for endpoint 'group_comment' with values ['author', 'content', 'group_post_id', 'id']. Did you forget to specify values ['group_id']?

127.0.0.1 - - [03/May/2022 22:47:23] "GET /groups/1/comments/1 HTTP/1.1" 500 -

Here are the 'group_likes' and 'group_comments' classes as examples:

GroupCommentAPI.py

from flask_restful import Resource, reqparse, abort, marshal

from classes.data_classes.groups.group_comments import group_comments, group_comment_fields


class GroupCommentAPI(Resource):
    def __init__(self):
        self.reqparse = reqparse.RequestParser()
        self.reqparse.add_argument('content', type=str, location='json')
        self.reqparse.add_argument('author', type=str, location='json')
        self.reqparse.add_argument('group_post_id', type=int, location='json')
        super(GroupCommentAPI, self).__init__()

    def get(self, group_id, id):
        group_comment = [group_comment for group_comment in group_comments if group_comment['id'] == id and group_comment['group_post_id'] == group_id]
        if len(group_comment) == 0:
            abort(404)
        return {'group_comment': marshal(group_comment[0], group_comment_fields)}

    def put(self, group_id, id):
        group_comment = [group_comment for group_comment in group_comments if group_comment['id'] == id and group_comment['group_post_id'] == group_id]
        if len(group_comment) == 0:
            abort(404)
        group_comment = group_comment[0]
        args = self.reqparse.parse_args()
        for k, v in args.items():
            if v is not None:
                group_comment[k] = v
        return {'group_comment': marshal(group_comment, group_comment_fields)}

    def delete(self, group_id, id):
        group_comment = [group_comment for group_comment in group_comments if group_comment['id'] == id and group_comment['group_post_id'] == group_id]
        if len(group_comment) == 0:
            abort(404)
        group_comments.remove(group_comment[0])
        return {'result': True}

GroupCommentListAPI.py

from flask_restful import Resource, reqparse, marshal

from classes.data_classes.groups.group_comments import group_comment_fields, group_comments


class GroupCommentListAPI(Resource):
    def __init__(self):
        self.reqparse = reqparse.RequestParser()
        self.reqparse.add_argument('content', type=str, required=True, help='No group comment content provided', location='json')
        self.reqparse.add_argument('author', type=str, required=True, help='No group comment author provided', location='json')
        self.reqparse.add_argument('group_post_id', type=int, required=True, help='No group post ID provided', location='json')
        super(GroupCommentListAPI, self).__init__()

    def get(self, id):
        return {'group_comments': [marshal(group_comment, group_comment_fields) for group_comment in group_comments if group_comment['group_post_id'] == id]}

    def post(self):
        args = self.reqparse.parse_args()
        group_comment = {
            'id': group_comments[-1]['id'] + 1 if len(group_comments) > 0 else 1,
            'content': args['content'],
            'author': args['author'],
            'group_post_id': args['group_post_id']
        }
        group_comments.append(group_comment)
        return {'group_comment': marshal(group_comment, group_comment_fields)}, 201

GroupLikeAPI.py

from flask_restful import Resource, reqparse, marshal, abort

from classes.data_classes.groups.group_likes import group_likes, group_like_fields


class GroupLikeAPI(Resource):
    def __init__(self):
        self.reqparse = reqparse.RequestParser()
        self.reqparse.add_argument('author', type=str, location='json')
        self.reqparse.add_argument('group_post_id', type=int, location='json')
        super(GroupLikeAPI, self).__init__()

    def get(self, group_id, id):
        group_like = [group_like for group_like in group_likes if group_like['id'] == id and group_like['group_post_id'] == group_id]
        if len(group_like) == 0:
            abort(404)
        return {'group_like': marshal(group_like[0], group_like_fields)}

    def put(self, group_id, id):
        group_like = [group_like for group_like in group_likes if group_like['id'] == id and group_like['group_post_id'] == group_id]
        if len(group_like) == 0:
            abort(404)
        group_like = group_like[0]
        args = self.reqparse.parse_args()
        for k, v in args.items():
            if v != None:
                group_like[k] = v
        return {'group_like': marshal(group_like, group_like_fields)}

    def delete(self, group_id, id):
        group_like = [group_like for group_like in group_likes if group_like['id'] == id and group_like['group_post_id'] == group_id]
        if len(group_like) == 0:
            abort(404)
        group_likes.remove(group_like[0])
        return {'result': True}

GroupLikeListAPI.py

from flask_restful import Resource, reqparse, marshal

from classes.data_classes.groups.group_likes import group_like_fields, group_likes


class GroupLikeListAPI(Resource):
    def __init__(self):
        self.reqparse = reqparse.RequestParser()
        self.reqparse.add_argument('author', type=str, required=True, help='No group like author provided', location='json')
        self.reqparse.add_argument('group_post_id', type=int, required=True, help='No group post ID provided', location='json')
        super(GroupLikeListAPI, self).__init__()

    def get(self, id):
        return {'group_likes': [marshal(group_like, group_like_fields) for group_like in group_likes if group_like['group_post_id'] == id]}

    def post(self):
        args = self.reqparse.parse_args()
        group_like = {
            'id': group_likes[-1]['id'] + 1 if len(group_likes) > 0 else 1,
            'author': args['author'],
            'group_post_id': args['group_post_id']
        }
        group_likes.append(group_like)
        return {'group_like': marshal(group_like, group_like_fields)}, 201

What is going wrong? What is causing the error? How could I fix it?

A greeting and thanks in advance.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source