Search code examples
restflaskflask-restfulhttp-method

Flask-RESTful specify HTTP methods allowed for specific endpoints


Consider that I have two Resource classes:

class UserView(Resource):
    def get(self, id):
        ...
    def post(self):
        ...
    def put(self, id):
        ...
    def delete(self, id):
        ...


class AnotherUserView(Resource):
    def get(self):
        ...
    def put(self):
        ...
    def delete(self):
        ...


api.add_resource(UserView, '/user/<int:id>')
api.add_resource(AnotherUserView, '/user')

Given the code above, the GET, PUT and DELETE methods of UserView all require a path parameter id. Therefore, UserView is mapped to the route /user/<int:id>. However, the POST method does not need the path parameter id but is included under the route that provides the param id, which will be confusing.

So now, I'm thinking if there is a way to specify which methods are allowed in a specific route (or endpoint), like what we can do with Flask: @app.route('/user/<int:id>', methods=['GET', 'PUT', 'DELETE'].

Expected what-I-can-do:

api.add_resource(UserView, '/user/<int:id>', methods=['GET', 'PUT', 'DELETE'])
api.add_resource(UserView, '/user', methods=['POST'])
api.add_resource(AnotherUserView, '/user', methods=['GET', 'PUT', 'DELETE'])

But this is actually not going to work, as the compiler tells me I'm overwriting view function UserView.

I read the doc of Flask-RESTful and found api.add_resource doesn't have an arg of methods that can be used to specify allowed HTTP methods as app.route does. Is there a way to achieve this?


Solution

  • In Flask-Restful the class functions get, post etc correspond to the http methods. If you don't want a particular method for a Resource simply leave it out.

    I personally don't find it confusing having the POST method without an id in the class.

    To get your expected outcome consider adding the desired routes for each resource. E.g.

    from flask_restful import Api, Resource
    
    class User(Resource):
        def get(self, id=None):
            if id:
                return "specific user"
            else:
                return "list of users"
    
        def post(self):
            return "post with no id!"
    
        def delete(self, id=None):
            if id:
                return "deleting user"
            else:
                return "need to specify a user"
    
    api.add_resource(User, '/user', '/user/<int:id>')