Python flask not working with url containing "?"

Question:

I am new to flask and I was trying to make GET request for url containing "?" symbol but it look like my program is just skipping work with it. I am working with flask-sql alchemy, flask and flask-restful. Some simplified look of my program looks like this:

fields_list = ['id']

db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
class Get(Resource):
    @staticmethod
    def get():
        users = User.query.all()
        usr_list = Collection.user_to_json(users)

        return {"Users": usr_list}, 200

class GetSorted(Resource):
    @staticmethod
    def get(field, type):
        if field not in fields_list or type not in ['acs', 'desc']:
            return {'Error': 'Wrong field or sort type'}, 400
        users = db.session.execute(f"SELECT * FROM USER ORDER BY {field} {type}")
        usr_list = Collection.user_to_json(users)
        return {"Users": usr_list}, 200
api.add_resource(GetSorted, '/api/customers?sort=<field>&sort_type=<type>')
api.add_resource(Get, '/api/customers')

Output with url "http://127.0.0.1:5000/api/customers?sort=id&sort_type=desc" looks like this

{
    "Users": [
        {
            "Id": 1
        },
        {
            "Id": 2
        },
        {
            "Id": 3
        },
    ]
}

But I expect it to look like this

{
    "Users": [
        {
            "Id": 3
        },
        {
            "Id": 2
        },
        {
            "Id": 1
        },
    ]
}

Somehow if I replace "?" with "/" in url everything worked fine, but I want it to work with "?"

Asked By: Sergio

||

Answers:

In order to get the information after ?, you have to use request.args. This information is Query Parameters, which are part of the Query String: a section of the URL that contains key-value parameters.

If your route is:

api.add_resource(GetSorted, '/api/customers?sort=<field>&sort_type=<type>')

Your key-values would be:

sort=<field>
sort_type=<type>

And you could get the values of the field and type keys like this:

sort = request.args.get('field', 'field_defaul_value')
sort_type = request.args.get('type', 'type_defaul_value')

More info:

Answered By: Asi

With Flask you can define path variables like you did, but they must be part of the path. For example, defining a path of /api/customers/<id> can be used to get a specific customer by id, defining the function as def get(id):. Query parameters cannot be defined in such a way, and as you mentioned in your comment, you need to somehow "overload" the get function. Here is one way to do it:

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

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

USERS = [
    {"id": 1},
    {"id": 3},
    {"id": 2},
]

class Get(Resource):
    @classmethod
    def get(cls):
        if request.args:
            return cls._sorted_get()
        return {"Users": USERS, "args":request.args}, 200

    @classmethod
    def _sorted_get(cls):
        field = request.args.get("sort")
        type = request.args.get("sort_type")
        if field not in ("id",) or type not in ['acs', 'desc']:
            return {'Error': 'Wrong field or sort type'}, 400
        sorted_users = sorted(USERS, key=lambda x: x[field], reverse=type=="desc")
        return {"Users": sorted_users}, 200

api.add_resource(Get, '/api/customers')


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

Here is Flask’s documentation regarding accessing request data, and Flask-Restful’s quickstart guide.

Answered By: micromoses