What is the correct way to handle queries for a Flask RESTful endpoint?

Issue

I am creating an API using Flask-RESTful, and am attempting to make a resource that returns all items in a database that are like a user defined string.

The endpoint for this resource is defined as:

api = Api(app)
api.add_resource(ItemsList, '/privateapi/item?query=<string:tag>')

And the resource itself is:

class ItemsList(Resource):

    def get(self, tag):
        search = f"%{tag}%"
        items = ItemModel.query.filter(ItemModel.item_name.like(search)).all()
        return {"items": [item.json() for item in items]}

The problem is that when I send a GET request to the endpoint http://127.0.0.1:5000/privateapi/item?query=appl I get a 404 response.

When I change the endpoint to api.add_resource(ItemsList, '/privateapi/item/<string:tag>') and then query the API I get the desired response.

However, I would prefer to use the query approach since I am not trying to GET a single record but want to return an array. I just think it makes more sense this way.

What could I try?

Solution

In flask, query parameters aren’t used to match routes (only the path part of the URL is relevant). When you write:

api.add_resource(ItemsList, '/privateapi/item?query=<string:tag>')

You have created a route that will never match (well, not exactly; see below).

You access query parameters in the request.args value, like this:

from flask import Flask, request
from flask_restful import Resource, Api

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


class ItemsList(Resource):
    def get(self):
        query = request.args.get("query")
        return f"Query expression was: {query}"


api.add_resource(ItemsList, "/privateapi/item")

if __name__ == "__main__":
    app.run(debug=True)

With the above code, if I write:

curl http://127.0.0.1:5000/privateapi/item?query=appl

I get as the response:

"Query expression was: appl"

When I said "You have created a route that will never match" this was actually a bit of lie. In fact, you have created a route that requires a literal ? in the URL path, so if you were to make a request for this URL:

curl http://127.0.0.1:5000/privateapi/item%3Fquery=appl

It would work, but it’s not what you want.

Answered By – larsks

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published