Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Behavior when querying subscription through incorrect protocol #1773

Closed
stephentuso opened this issue Mar 5, 2019 · 6 comments
Closed

Behavior when querying subscription through incorrect protocol #1773

stephentuso opened this issue Mar 5, 2019 · 6 comments
Labels

Comments

@stephentuso
Copy link

For a subscription field, resolve is called with the source parameter set to whatever is yielded from the subscribe async iterator. However, I noticed that when a subscription field is queried from a server not using subscribe, it behaves as if it is a query field; resolve is called and the source parameter is set to rootValue.

Is it supposed to even be possible to query subscription in that case? It seems like it would be appropriate to return an error there. Is this something that is expected to be handled outside of this library?

@IvanGoncharov
Copy link
Member

IvanGoncharov commented Mar 5, 2019

Is it supposed to even be possible to query subscription in that case? It seems like it would be appropriate to return an error there. Is this something that is expected to be handled outside of this library?

@stephentuso If your subscription root is reachable from query root then it's expected behavior.
If you want to forbid such behavior please use a separate type for subscription root and don't reference it inside other types.

@stephentuso
Copy link
Author

stephentuso commented Mar 10, 2019

@IvanGoncharov Thanks, unless I'm misunderstanding, the query root isn't involved here so I don't think that applies. Let me clarify with a (contrived) example:

const { GraphQLObjectType, GraphQLSchema, GraphQLString, graphql, parse, subscribe } = require('graphql');

// Note that resolve just returns the source 
// When queried through `subscribe`, it's the yielded value
// When queried through `graphql`, it's the root value
const subscription = new GraphQLObjectType({
  name: 'Subscription',
  fields: {
    subscriptionField: {
      type: GraphQLString,
      resolve(value) { return value },
      subscribe: async function* () {
        yield 'A';
        yield 'B';
      }
    }
  }
});

// Irrelevant, but required
const query = new GraphQLObjectType({
  name: 'Query',
  fields: {
    queryField: {
      type: GraphQLString,
      resolve() {
        return 'Required query field';
      }
    }
  }
});

const schema = new GraphQLSchema({
  query,
  subscription,
});

async function main() {
  const rootValue = 'ROOT VALUE';

  const subscriptionQuery = `
    subscription {
      subscriptionField
    }
  `;

  const document = parse(subscriptionQuery);

  const subscribeResult = await subscribe(schema, document, rootValue);

  // Logs 'A' and 'B' as expected
  for await (const result of subscribeResult) {
    console.log(result.data.subscriptionField);
  }

  const graphqlResult = await graphql(schema, subscriptionQuery, rootValue);

  // Logs 'ROOT VALUE'
  console.log(graphqlResult.data.subscriptionField);
}

main().catch(console.log);

So, you can see the subscription type can be queried from graphql (as it would be through a HTTP server) and it's treated as if it is the query type - resolve is called with 'ROOT VALUE'.

Basically - should it be possible to query the subscription type with the graphql function? Shouldn't it only work with subscribe?

@IvanGoncharov IvanGoncharov reopened this Mar 10, 2019
@IvanGoncharov
Copy link
Member

@stephentuso Thanks for the example 👍
I need to do some research before answering this question or changing graphql behavior.

As I understand it's not a critical issue for your use case, but just a confusing behavior of graphql function that you discovered during development. Right?

@stephentuso
Copy link
Author

stephentuso commented Mar 11, 2019

Correct - I was trying out subscriptions, accidentally queried it through http, and was confused by the response. Not something that should be an issue in an actual app

@yaacovCR
Copy link
Contributor

execute basically runs the executeSubscriptionEvent algorithm when it comes to subscriptions, and the graphql method just wraps execute, so this is known current behavior, if not obvious. When the execute and subscribe functions are eventually combined, the graphql method should probably be changed.

@yaacovCR
Copy link
Contributor

See: #2144

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants