Skip to main content

__typename is not valid at subscription root

At a glance

Timeline


I'm writing up some of the GraphQL "query ambiguity" work currently and noticed this issue in the spec. In the case of a subscription it seems that

subscription {
__typename
}

does not correctly get evaluated by the reference implementation during subscriptions (though you can query it with graphql(...) you can't access it via subscribe(...)). It doesn't really make sense to request __typename here since it's not ever going to change during the life of the schema, and subscriptions only support one root-level field, however I thought it was worth highlighting.

Reproduction with GraphQL-js (toggle which doc is commented to see a functioning subscription):

const {
GraphQLSchema,
GraphQLObjectType,
GraphQLInt,
GraphQLFloat,
parse,
validate,
subscribe,
} = require("graphql");

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

async function* everySecond() {
for (let i = 0; i < 1000; i++) {
yield i;
await sleep(1000);
}
}

const Query = new GraphQLObjectType({
name: "Query",
fields: {
a: {
type: GraphQLInt,
},
},
});

const Subscription = new GraphQLObjectType({
name: "Subscription",
fields: {
ts: {
type: GraphQLFloat,
subscribe() {
return everySecond();
},
resolve() {
return Date.now();
},
},
},
});

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

async function main() {
const doc = parse("subscription { __typename }");
// const doc = parse("subscription { ts }");
const errors = validate(schema, doc);
if (errors && errors.length) {
console.dir(errors);
throw new Error("Errors occurred");
}
const result = await subscribe(schema, doc);
console.dir(result);
for await (const r of result) {
console.dir(r);
}
}

main().catch(e => {
console.dir(e);
process.exit(1);
});

Produces this error:

Error: Subscription field must return Async Iterable. Received: undefined
at [...]/node_modules/graphql/subscription/subscribe.js:169:13
at async main ([...]/test.js:57:18)