Какое api и имплементация должны быть для REST коллекций в python?

Меня не устроили rest фреймворки, которые имеются в питоне, и я пытаюсь написать свой на flask (хотя видимо правильнее было бы использовать falcon, как мне теперь кажется).

На данный момент я написал примерно следующую имплементацию.

Возник вопрос, что делать в случае если если есть коллекции элементы которой могут тоже содержать коллекции, а пользователь не хочет получать развернутые коллекции.
В фейсбуке используют 'fields' в queryset, чтобы пользователь мог сам выбрать какие поля ему нужны. Но что если пользователь хочет исключить поля в коллекции уровнем ниже (на один, на два, на сколько угодно уровней)?

Допустим в таком примере для наглядности.

/market/labels/id/products/id/reviews

Пока самым универсальным вариантом мне видится возвращение курсора для всех коллекций без исключения.

Я попытался написать нечто рабочее, но оно работает только если запросить products/id/?fields&every, field,except,reviews, а если запросить produсts, то пользователь все равно увидит reviews у каждого product. Конечно я могу написать проверку типа "если нужно удалить поля, то если ответ является словарем, удали поля из словаря, а если списком словарей, то удали поля в каждом словаре в списке", но это выглядит убого и будет работать только на один уровень глубины. Можно пройтись по всему дереву словарей и удалить поля, но тогда пользователю надо задавать полные пути полей, которые ему нужны.

<code>class ResourceInterface(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def get_path(self):
        pass

    @abstractmethod
    def set_path(self, path):
        pass

    @abstractmethod
    def on_get(self, *args, **kwargs):
        pass

    @abstractmethod
    def on_post(self, *args, **kwargs):
        pass

    @abstractmethod
    def on_delete(self):
        pass

    @abstractmethod
    def on_put(self):
        pass

    @abstractmethod
    def do_put(self):
        pass

    @abstractmethod
    def do_post(self, *args, **kwargs):
        pass

    @abstractmethod
    # returns serializable result e.g. dict or list or primitive
    def do_get(self, *args, **kwargs):
        pass

    @abstractmethod
    def do_delete(self, *args, **kwargs):
        pass


class BaseResource(ResourceInterface):
    __metaclass__ = ABCMeta

    def __init__(self, repository, entity_serializer, path=None):
        self.entity_serializer = entity_serializer
        self.repository = repository
        self.path = None
        self.set_path(path)
        self.pickler = Pickler(unpicklable=False)

    def on_put(self):
        pickled_output = self.pickler.flatten(self.do_put())
        return jsonpickle.json.encode(pickled_output)

    def on_post(self, *args, **kwargs):
        pickled_output = self.pickler.flatten(self.do_post(*args, **kwargs))
        return jsonpickle.json.encode(pickled_output)

    def on_get(self, *args, **kwargs):
        try:
            pickled_output = self.pickler.flatten(self.do_get(*args, **kwargs))
            fields = request.args.get('fields')
            if fields:
                for field in pickled_output.keys():
                    if field not in fields:
                        del pickled_output[field]
            return jsonpickle.json.encode(pickled_output)
        except ResourceNotFoundError as e:
            return str(e), 404

    def on_delete(self, *args, **kwargs):
        pickled_output = self.pickler.flatten(self.do_delete(*args, **kwargs))
        return jsonpickle.json.encode(pickled_output)

    def get_path(self):
        return self.path

    def set_path(self, path):
        self.path = path


class ResourceDecorator(ResourceInterface):
    def do_delete(self, *args, **kwargs):
        return self.implementation.do_delete()

    def do_get(self, *args, **kwargs):
        return self.implementation.do_get()

    def do_post(self, *args, **kwargs):
        return self.implementation.do_post()

    def do_put(self):
        return self.implementation.do_put()

    def set_path(self, path):
        self.implementation.set_path(path)

    def get_path(self):
        return self.implementation.get_path()

    def on_post(self, *args, **kwargs):
        return self.implementation.on_post(args, kwargs)

    def on_get(self, *args, **kwargs):
        return self.implementation.on_get(args, kwargs)

    def on_delete(self):
        return self.implementation.on_delete()

    def on_put(self):
        return self.implementation.on_put()

    def __init__(self, implementation):
        """

        :type implementation: BaseResource
        """
        self.implementation = implementation




class FieldedResourceDecorator(ResourceDecorator):
    def do_get(self, *args, **kwargs):
        result = super(FieldedResourceDecorator, self).do_get(*args, **kwargs)</code>
  • Вопрос задан
  • 454 просмотра
Пригласить эксперта
Ответы на вопрос 1
@bromzh
Drugs-driven development
Но что если пользователь хочет исключить поля в коллекции уровнем ниже
Используй точку, потом рассматривай включаемые/исключаемые поля рекурсивно.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы