REST API Filtrowanie wyników z bazy za pomocą parametrów URL

0

Cześć, ponownie przychodzę z pytaniem o Flaska, a może bardziej o to jak rozwiązać filtrowanie wyników z bazy danych na podstawie query string. Chodzi mi o endpointy jak poniżej wraz z operatorami gt, lt, gte, lte (operatorów jeszcze nie mam):

/api/users
zwraca JSON z wszystkimi użytkownikami

/api/users?name=John
zwraca JSON z użytkownikami o imieniu John

/api/users?name=John&age=40
zwraca JSON z użytkownikami o imieniu John i wieku 40

/api/users?age=40&country=Poland&city=Warsaw
zwraca JSON z użytkownikami w wieku 40, kraju Poland, miasta Warsaw

/api/users?age[gt]=40
zwraca JSON z użytkownikami w wieku większym od 40

/api/users?page=1&limit=5
paginacja zwracanych danych

Robię API we flask_restful + mongoengine, które zaproponowano w innym wątku i mam coś w tym stylu:

class UsersApi(Resource):
    def get(self):
        try:
            page = 1
            limit = 10
            skip = (page - 1) * limit
            # query string
            name = request.args.get('name')
            # more...

            if request.args is not None:
                filters = {}

            if 'page' in request.args and 'limit' in request.args:
                page = int(request.args.get('page'))
                limit = int(request.args.get('limit'))
                skip = (page - 1) * limit

            if 'name' in request.args:
                filters['name'] = name

            # more URL parameters...

            users_query = User.objects(**filters).skip(skip).limit(limit)
            users = users_query.to_json()
            return Response(users, mimetype='application/json', status=200)
        except Exception:
            raise InternalServerError

Po kolei sprawdzam w request.args czy istnieje dany klucz, jeśli tak wtedy dodaję wartość parametru URL do słownika. Na końcu słownik filtrów jest przekazywany do metody User.objects() i robię rozpakowanie słownika. Jako tako wydaje się, że działa lecz nie wiem czy idę w dobrym kierunku :P

Zależy mi na filtrowania jak w endpointach powyżej, nie wiem w sumie jak coś takiego najlepiej osiągnąć, bo jak widać ręcznie muszę ustawiać dozwolone klucze, które przecież mogą się zmienić. Ogólnie to dopiero zaczynam z tworzeniem takich API, a nie ukrywam, że chciałbym zrozumieć jak się np. tworzy takie coś od podstaw.

Operatorów gt, lt, gte, lte jeszcze nie zrobiłem, ale mam podobny przykład z innej technologii i tam jest to zrobione na podstawie wyrażenai regularnego, lecz w Pythonie chyba inaczej trzeba będzie to zrobić.

3

Nie programuje w pytongu ale ponoć można od razu wyłuskać słownik z parametrów geta zamiast robić to tak jak Ty.
https://stackoverflow.com/questions/41229710/flask-request-args-get-get-all-params-python/41229732

1

Jak wyżej: wydobywasz od razu cały słownik parametrów zamiast go mozolnie budować, potem przepuszczasz przez walidator, aby kontrolować, co userzy wprowadzają (marshmallow lub Cerberus), na końcu wrzucasz do QuerySet, więc lepiej zamienić nazwy parametrów age[gt] na age__gt aby nie trzeba tego było dodatkowo tłumaczyć przy rozpakowywaniu.

Jest też coś takiego jak RequestParser, którym można wydobywać parametry z API. Wprawdzie piszą, że jest deprecated, ale to samo pisali też 3 lata temu więc chyba faktycznie nieprędko się tego pozbędą :D

1 użytkowników online, w tym zalogowanych: 0, gości: 1