Search code examples
pythonflaskflask-restful

What is the difference in configuring the end points using app.route() and api.add_resource() in a Python Flask application?


I am learning Python-Flask and found out that there are two ways to create endpoints in an application.

1. app.routing(/endpoint)
2. api.add_resource(CLASSNAME, endpoint)

Using app.routing() we can just add an endpoint over a method and invoke it. Using api.add_resource() we need to register the class name & the end points.

I've seen that the method names are given as get() & put() if you are using api.add_resource() For ex:

app = Flask(__name__)
api = Api(app)
vehicles = []

class VehicleData(Resource):    
    parser = reqparse.RequestParser()
    parser.add_argument('vehicle', type=str, required=True, help='name cannot be empty')
    parser.add_argument('type', type=str, required=True, help='vehicle type cannot be empty')
    parser.add_argument('wheels', type=int, required=True, help='number of wheels cannot be empty')
    parser.add_argument('suv', type=bool, required=False, help='SUV or not can be empty')

    def get(self, name):
        vehicle = next(filter(lambda x: x['name'] == name, vehicles), None)
        return {'vehicle': vehicle}, 200 if vehicle else 404

    def post(self, name):
        # data = request.get_json()
        # sport.append({'sportname': data['sport_name'], 'team_size':data['team_size'], 'popularity':data['popularity']})
        if next(filter(lambda x: x['name'] == name, vehicles), None) is not None:
            print("in the IF BLOCK")
            return {'message': 'The vehicle {n} already exists in the database'.format(n=name)}, 404

        v_data = VehicleData.parser.parse_args()
        vehicle = {'name': name, 'type':v_data['type'],  'vehicle': v_data['vehicle'], 'suv': v_data['suv'], 'wheels': v_data['wheels']}
        vehicles.append(vehicle)
        return vehicle, 201

    def getallvehicles(self):
        return {'vehicles': vehicles}

api.add_resource(VehicleData, '/addvehicle/<string:name>', '/getvehicle/<string:name>')
app.run(port=5000, debug=True)

If I submit the API http://127.0.0.1:5000/getvehicle with a GET http call, I am properly getting the data as per the logic given in the code. In the code I have only one GET & POST method. So Flask is automatically invoking the get() when I submit http://127.0.0.1:5000/getvehicle/<name> with a GET request.

What if I have a method name other than get()/post()/put() ? For example, if I have a method getallvehicles() that returns all the vehicles i.e returns the list vehicles, how can I register it in api.register() ?

For example, I tried this:

api.add_resource(VehicleData, '/addvehicle/<string:name>', '/getvehicle/<string:name>', '/getallvehicles')

and submitted the API call 'http://127.0.0.1:5000/getallvehicles` with a GET request, I am facing an error:

 File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask_restful/__init__.py", line 583, in dispatch_request
    resp = meth(*args, **kwargs)
TypeError: get() missing 1 required positional argument: 'name'

Could anyone tell me what is the mistake I did here and how can I give an endpoint for getallvehicles() in the below line and map it to a GET http request:

api.add_resource(VehicleData, '/addvehicle/<string:name>', '/getvehicle/<string:name>', '/getallvehicles')

Solution

  • The difference between the 2 different ways is, that:

    This one is "native" flask method, that you can use to wrap your functions with.

    @app.routing('/endpoint')
    

    This one is a part of the restfull_flask package and it does the things in a different way than the native flask way.

    api.add_resource(CLASSNAME, endpoint)
    

    You can do the same stuff with both ways, but if you use the rest_framework, then you should use the second method :)

    For the rest of your question I am sure you will find answers in this documentation: https://flask-restful.readthedocs.io/en/latest/