Подписка сервера Apollo, вложенная в тип

Я пытаюсь заставить распознаватель подписки работать в Apollo Server 2. Подписка работает, когда это поле верхнего уровня (т.е. непосредственно под Subscription в корне schema).

Однако, если подписка содержится в другом type, я всегда получаю сообщение об ошибке Subscription field must return Async Iterable. Received: undefined при подключении клиента к веб-сокету - преобразователь сервера никогда не запускается.

т.е. эта схема работает:

type Subscription {
  postAdded: Post
}

но этого нет:

type Subscription {
  post: PostSubscription
}

type PostSubscription {
  postAdded: Post
}

Мой преобразователь для второго случая выглядит так, но я безуспешно пробовал кучу разных вариантов:

Subscription: {
  post: () => ({
    PostSubscription: {}
  })
},
PostSubscription: {
  postAdded: {
    subscribe: () => pubSub.asyncIterator(['postAdded'])
  }
}

person Raman    schedule 15.08.2018    source источник
comment
Спасибо, что разместили этот вопрос, мы наблюдаем точно такое же поведение, я оказал нам услугу и клонировал ваш вопрос здесь: github.com/apollographql/graphql-subscriptions/issues/169   -  person 4F2E4A2E    schedule 21.08.2018


Ответы (1)


Сообщение об ошибке означает, что ваш почтовый преобразователь


    Subscription: {
      post: () => ({
        PostSubscription: {} // This needs to return AsyncIterator
      })
    },

Если я вас правильно понял, вы хотите подписаться на postAdded, postDeleted, postUpdated, все три под постом. Я понимаю, что вы хотите попробовать разместить их в пространстве имен в рамках той же модели, что лучше поможет организации. Но есть некоторые проблемы, я объясню их позже.

Совет из одного предложения: эти 3 поля лучше располагать непосредственно под полем корневой подписки.

Не сказать, что вы не можете этого сделать, но если вы действительно хотите, предположим, вы оформляете подписку


    Subscription{
      post{
         postAdded: Post
         postDeleted: Post
         postUpdated(id:Int!): Post
      }
    }

Тогда все три вложенных поля «совместно используют» один и тот же канал.

Тогда вам нужно сделать пару вещей.

  1. Функция подписки для публикации возвращает асинхронный итератор, но не postAdd, а поле post.

    Subscription: {
        post: {
            subscription: () =>  pubSub.asyncIterator(['postChannel'])
        }
    }

  1. Затем в функции мутации пост-мутации (добавление, обновление, удаление) вам нужно будет выяснить, что отправлять клиенту.

что-то вроде этого


    Mutation{
       createPost: (_,args,context,info)=>{
          const createdObject = // do create
          pubsub.publish("postChannel", {
             post:{
                // do not do postUpdate, postDelete, because there's nothing updated, deleted
                postAdded:createdObject
             }
          })
       }
    }

Это сделает то, что вы хотите, вроде работы, но здесь есть несколько проблем. 1. Каждый раз, когда происходит обновление / создание / удаление, клиент получает уведомление. Возможно, это даст клиенту неверную информацию. Вроде так Если клиент подписывается на

subscription{
    post{
        postAdded
    }
}

Затем, когда кто-то еще обновил сообщение, клиент получит такой ответ

response = {
    subscription:{
        postAdded:null
    }
}

Вероятно, можно игнорировать null для postAdd. Но для postUpdate это определенно будет проблемой. Представьте, что пользователь подписывается на

subscribe{
    post{
        postUpdate(id:1)
    }
}

Затем кто-то добавил сообщение, клиент всегда будет получать уведомление, потому что три события были связаны с одним и тем же каналом. Тогда он получит

response = {
    subscription:{
        postUpdated:null
    }
}

Затем, если вы используете клиент apollo, он удалит сообщение: 1 из кеша, потому что будет думать, что сообщение является нулевым.

Из-за этих проблем настоятельно рекомендуется создать много каналов, предпочтительно по три канала на модель. И создайте три подписки корневого уровня вместо их вложенности.

Для минимальной рабочей подписки я бы перенаправил вас на git-репо, которое я сделал для демонстрации подписки https://github.com/hansololai/apollo_subscription_boilerplate

person Evilsanta    schedule 07.03.2019