Apollo-server: Error in apollo-server-express: Subscription field must return Async Iterable. Received: undefined

Created on 6 May 2019  ยท  8Comments  ยท  Source: apollographql/apollo-server

I'm trying to implement subscriptions with apollo-server-express. From graphql-playground I receive the following error...

{
  "error": {
    "message": "Subscription field must return Async Iterable. Received: undefined"
  }
}

Until now I had not had problems with queries and mutations. I also had no errors with subscriptions using apollo-server. But I do have them with apollo-server-express.

This is the code:

const {gql, ApolloError, PubSub} = require('apollo-server-express');

// Mongoose models
const NoteModel = require('../../mongoose/NoteModel');

// Instance PubSub (publications and subscriptions)
const pubsub = new PubSub();

// Subscriptions tags
const NOTE_ADDED = 'NOTE_ADDED';


// Type definitions define the "shape" of your data and specify
// which ways the data can be fetched from the GraphQL server.
const typeDefs = gql`
    type Note {
        _id: Int
        title: String
        description: String
    }

    input NoteInput {
        title: String
        description: String
    }

    # The "Query" type is the root of all GraphQL queries.
    # Using extend is particularly useful in avoiding a large 
    # list of fields on root Queries and Mutations
    # More info: https://www.apollographql.com/docs/graphql-tools/generate-schema#extend-types
    extend type Query {
        listNotes: [Note]
    }

    extend type Mutation {
        addNote(input: NoteInput) : Note!,
        updateNote(
            id: Int!,
            input: NoteInput
        ): Note!,
        deleteNote(id: Int!): Boolean!
    }

    extend type Subscription {
        noteAdded: [Note]
    }
`;


const resolvers = {
    Query: {
        listNotes: async (parent, args, context, info) => {

        }
    },
    Mutation: {
        addNote: (parent, args, context, info) => {
            pubsub.publish(NOTE_ADDED, { noteAdded: args.input });
            return NoteModel.create(args.input);
        },
        updateNote: (parent, args, context, info) => {

        },
        deleteNote: (parent, args, context, info) => {

        }
    },
    Subscription: {
        noteAdded: {
            subscribe: () => pubsub.asyncIterator([NOTE_ADDED]),
        },
    },
};


module.exports = {
    typeDefs,
    resolvers
};

Most helpful comment

@abernix It is definitely a bug! And I did some investigation.

  1. @LaurenceM10 wrote that it works with new ApolloServer({ typeDefs, resolvers }), but it does not with new ApolloServer({ modules })

  2. In my case it does not work with new ApolloServer({ schema })

So, I found where the problem appears:
http://center.koryagin.com/i/2019-08-04_00:29:39_6df691.png

And with this trivial monkey-patching everything is working, subscription messages arrive in browser.

const schema = buildFederatedSchema(federationSources);
schema._subscriptionType._fields.messageCreated.subscribe = 
  federationSources[11].resolvers.Subscription.messageCreated.subscribe;

All 8 comments

In the definition of the scheme I call the typedefs and the resolvers and additionally what is required for the subscriptions to work in apoll-server-express

server.applyMiddleware({app});
const httpServer = http.createServer(app);
server.installSubscriptionHandlers(httpServer);

httpServer.listen(PORT, () => {
    console.log(`๐Ÿš€ Server ready at http://localhost:${PORT}${server.graphqlPath}`);
    console.log(`๐Ÿš€ Subscriptions ready at ws://localhost:${PORT}${server.subscriptionsPath}`);
});

๐Ÿ‘‹ I'll close this since this doesn't appear to be a bug with Apollo Server, but rather a question about how to use it or one of its components.

Rather than asking it here in GitHub Issues โ€” where efforts are focused on fixing bugs and adding new features โ€” I'd ask that you take this question to the _Apollo Server_ channel within the Apollo community on Spectrum.chat where there are community members who might be able to relate to a similar problem, or might be able to help you out more interactively. Thanks for your understanding!

I solved this by passing typedefs and resolvers to ApolloServer instead of passing them as modules.

const server = new ApolloServer({
    typeDefs: [NoteType, BookType],
    resolvers: [NoteResolver, BookResolver],
})

Before this, the syntax was as follows.

const server = new ApolloServer({
    modules: [
        require('./schema/notes/'),
        require('./schema/books/'),
    ],
})

It should be mentioned that queries and mutations with the syntax

modules: [
        require('./schema/notes/'),
        require('./schema/books/'),
    ],

work well, however with subscriptions there is an error.

I think I am running into this same issue with subscriptions and Typescript.

@Falieson I already solved it, I think you could reproduce the error in a repository and that might help you.

@abernix It is definitely a bug! And I did some investigation.

  1. @LaurenceM10 wrote that it works with new ApolloServer({ typeDefs, resolvers }), but it does not with new ApolloServer({ modules })

  2. In my case it does not work with new ApolloServer({ schema })

So, I found where the problem appears:
http://center.koryagin.com/i/2019-08-04_00:29:39_6df691.png

And with this trivial monkey-patching everything is working, subscription messages arrive in browser.

const schema = buildFederatedSchema(federationSources);
schema._subscriptionType._fields.messageCreated.subscribe = 
  federationSources[11].resolvers.Subscription.messageCreated.subscribe;

Plus, it needs a dummy resolver in this case.

Eventual project-level fix looks like this (_ is lodash):

  const schema = buildFederatedSchema(federationSources);

  // Hooray! Monkey-patching!
  federationSources.forEach(({ resolvers }) => {
    if (resolvers.Subscription) {
      _.forEach(resolvers.Subscription, (resolver, field) => {
        if (_.isPlainObject(resolver) && resolver.subscribe) {
          const target = schema._subscriptionType._fields[field];

          // Ensure everything is still as bad, as we expect
          if (target.subscribe) {
            throw new Error('The library might be fixed. Delete this patch.');
          }

          // Do patch
          target.subscribe = resolver.subscribe;
          if (!target.resolve) {
            target.resolve = x => x;
          }
        }
      });
    }
  });

Can someone please open this issue? this still happens a year after it was reported and closed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Magneticmagnum picture Magneticmagnum  ยท  3Comments

nevyn-lookback picture nevyn-lookback  ยท  3Comments

dupski picture dupski  ยท  3Comments

dobesv picture dobesv  ยท  3Comments

deathg0d picture deathg0d  ยท  3Comments