Организация кода graphql для масштабируемых проектов

Подумайте, что у нас есть большой проект с множеством приложений, который приводит к множеству запросов и мутаций. Для таких проектов, как вы, люди, обращаетесь с архитектурой кода graphql. Возьмем пример.

У меня есть приложение под названием Accounts. В нем будут запросы и изменения, связанные с пользователем и профилем. Структура папок, которую я использую, заключается в том, что каждое приложение будет иметь папку graphql, которая затем будет иметь schema.py и mutations.py. Код пока устроен примерно так

schema.py

class User(DjangoObjectType):

    class Meta:
        model = CustomUser
        filter_fields = {
            'email': ['exact', ],
        }
        exclude_fields = ('password', 'is_superuser', )
        interfaces = (relay.Node, )


class ProfileNode(DjangoObjectType):

    class Meta:
        model = Profile
        interfaces = (relay.Node, )


class UserQuery(object):

    user = relay.Node.Field(User)
    users = DjangoFilterConnectionField(User)  # resolve_users is not needed now


class ProfileQuery(object):

    profile = relay.Node.Field(ProfileNode)
    profiles = DjangoFilterConnectionField(ProfileNode)


class UserProfile(ObjectType):

    profile = Field(ProfileNode)

    def resolve_profile(self, info, **kwargs):
        if id is not None and info.context.user.is_authenticated:
            profile = Profile.objects.get(user=info.context.user)
            return profile
        return None


class Viewer(ObjectType):

    user = Field(User)

    def resolve_user(self, info, **kwargs):
        if info.context.user.is_authenticated:
            return info.context.user
        return None 

mutations.py

class Register(graphene.Mutation):
    """
    Mutation to register a user
    """
    class Arguments:

        first_name = graphene.String(required=True)
        last_name = graphene.String(required=True)
        email = graphene.String(required=True)
        password = graphene.String(required=True)
        password_repeat = graphene.String(required=True)

    success = graphene.Boolean()
    errors = graphene.List(graphene.String)

    def mutate(self, info, first_name, last_name, email, password, password_repeat):
        # console.info('info', info, first_name, last_name, email, password)
        if password == password_repeat:
            try:
                user = CustomUser.objects.create(
                    first_name=first_name,
                    last_name=last_name,
                    email=email,
                    is_active=False
                    )
                print ('user', user)
                user.set_password(password)
                user.save()
                if djoser_settings.get('SEND_ACTIVATION_EMAIL'):
                    send_activation_email(user, info.context)
                return Register(success=bool(user.id))
            # TODO: specify exception
            except Exception:
                errors = ["email", "Email already registered."]
                return Register(success=False, errors=errors)
        errors = ["password", "Passwords don't match."]
        return Register(success=False, errors=errors)

корневая схема

// just to show the number of mutations just for account apps.
from accounts.graphql.mutations import (
    Activate,
    DeleteAccount,
    Login,
    RefreshToken,
    Register,
    ResetPassword,
    ResetPasswordConfirm,
    )
from accounts.graphql.schema import Viewer, UserProfile


class Mutation(company_mutation.Mutation, graphene.ObjectType):

    activate = Activate.Field()
    debug = graphene.Field(DjangoDebug, name='__debug')


class Query(company_schema.Query, graphene.ObjectType):
    viewer = graphene.Field(Viewer)
    user_profile = graphene.Field(UserProfile)
    debug = graphene.Field(DjangoDebug, name='__debug')

    @staticmethod
    def resolve_viewer(self, info, **kwargs):
        if info.context.user.is_authenticated:
            return info.context.user
        return None

    @staticmethod
    def resolve_user_profile(self, info, **kwargs):
        if info.context.user.is_authenticated and id:
            return info.context.user
        return None


schema = graphene.Schema(query=Query, mutation=Mutation)

вы можете видеть мутации только для приложений учетных записей. Мутаций много, и их будет больше, если рассматривать все приложения. Как вы справляетесь с такими?

См. stackoverflow.com/questions/45226398/…

Mark Chackerian 17.10.2018 07:10
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
1
859
1

Ответы 1

Я считаю, что организация проекта, основанная только на файлах типа schema.py, queries.py, mutations.py, очень плохо для большого проекта.

Это похоже на организацию частей вашей модели с помощью таких файлов, как models.py, fields.py, utils.py ...

В частности, GraphQL ObjectType, определенный где-то в вашем файле queries.py, может быть возвращен или использован в качестве входных данных при мутации.

Поэтому я предпочитаю структуру, больше основанную на объектах и ​​их логических отношениях.

schema/
    __init__.py : contains your root schema actual code
    viewer.py : contains the ObjectType Viewer
    user/
        user.py : contains the ObjectType User and UserQuery
        profile.py : contains the ObjectType Profil
        account : contains the account management mutations
    login.py : contains the login / logout mutations
...

Примечание: вы можете внедрять мутации так же, как и запросы, чтобы иметь возможность получать такие запросы мутаций, как:

mutation {
    account {
        delete(id: 12) {
            status
        }
    }
}

Не могли бы вы добавить код Python, который показывает, как организовать подобные мутации?

eltiare 16.06.2019 03:59

Другие вопросы по теме