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

gateway looses oneOf directive: Cannot query field "isOneOf" on type "__Type" #3204

Open
mac2000 opened this issue Jan 24, 2025 · 0 comments

Comments

@mac2000
Copy link

mac2000 commented Jan 24, 2025

Issue Description

Let's pretend we have following schema:

directive @oneOf on INPUT_OBJECT

type Query {
  users(where: UserWhere!): [User!]!
}

type User {
  id: ID!
  username: String
}

input UserWhere @oneOf {
  foo: Int
  bar: Int
}

Nothing interesting or special here

for this schema we have single subgraph service

subgraph.mjs
import { ApolloServer } from '@apollo/server'
import { startStandaloneServer } from '@apollo/server/standalone'
import { parse } from 'graphql'
import { buildSubgraphSchema } from '@apollo/subgraph' // added for federation

const typeDefs = parse(`#graphql
  directive @oneOf on INPUT_OBJECT

  type Query {
    users(where: UserWhere!): [User!]!
  }

  type User {
    id: ID!
    username: String
  }

  input UserWhere @oneOf {
    foo: Int
    bar: Int
  }
`)

const resolvers = {
  Query: {
    users: () => [{ id: '1', username: '@mac' }],
  },
}

const server = new ApolloServer({
  schema: buildSubgraphSchema({ typeDefs, resolvers }), // federated graphql server, instead of `typeDefs, resolvers`
})
startStandaloneServer(server).then(({ url }) => console.log(`open ${url}`))

both { __type(name: "UserWhere") { name isOneOf } } and { _service { sdl } } works and returns one of

Problem

but, when we are on gateway land

supergraph.mjs
import { ApolloServer } from '@apollo/server'
import { ApolloGateway, IntrospectAndCompose } from '@apollo/gateway'
import { startStandaloneServer } from '@apollo/server/standalone'

const gateway = new ApolloGateway({
  supergraphSdl: new IntrospectAndCompose({
    subgraphs: [{ name: 'demo', url: 'http://localhost:4000' }],
  }),
})

const server = new ApolloServer({ gateway })
startStandaloneServer(server, { listen: { port: 3000 } }).then(({ url }) => console.log(`open ${url}`))

our attempt to run the same query fails with an error:

Cannot query field "isOneOf" on type "__Type".
full error with stack trace
{
  "errors": [
    {
      "message": "Cannot query field \"isOneOf\" on type \"__Type\".",
      "extensions": {
        "code": "INVALID_GRAPHQL",
        "stacktrace": [
          "GraphQLError: Cannot query field \"isOneOf\" on type \"__Type\".",
          "    at Object.err (/Users/mac/Desktop/oneoff/supergraph/node_modules/@apollo/federation-internals/dist/error.js:11:32)",
          "    at validate (/Users/mac/Desktop/oneoff/supergraph/node_modules/@apollo/federation-internals/dist/operations.js:15:46)",
          "    at selectionOfNode (/Users/mac/Desktop/oneoff/supergraph/node_modules/@apollo/federation-internals/dist/operations.js:2386:13)",
          "    at selectionSetOfNode (/Users/mac/Desktop/oneoff/supergraph/node_modules/@apollo/federation-internals/dist/operations.js:2366:24)",
          "    at selectionOfNode (/Users/mac/Desktop/oneoff/supergraph/node_modules/@apollo/federation-internals/dist/operations.js:2389:19)",
          "    at selectionSetOfNode (/Users/mac/Desktop/oneoff/supergraph/node_modules/@apollo/federation-internals/dist/operations.js:2362:43)",
          "    at parseSelectionSet (/Users/mac/Desktop/oneoff/supergraph/node_modules/@apollo/federation-internals/dist/operations.js:2472:26)",
          "    at operationFromAST (/Users/mac/Desktop/oneoff/supergraph/node_modules/@apollo/federation-internals/dist/operations.js:2456:55)",
          "    at operationFromDocument (/Users/mac/Desktop/oneoff/supergraph/node_modules/@apollo/federation-internals/dist/operations.js:2448:12)",
          "    at /Users/mac/Desktop/oneoff/supergraph/node_modules/@apollo/gateway/dist/index.js:78:100"
        ]
      }
    }
  ]
}

And indeed, deep inside it fails to retrieve such field here:

const definition = fieldAccessor(parentType, node.name.value);

it returns undefined and because of that everything else fails

Link to Reproduction

https://gist.github.com/mac2000/510f1d26e9dd562a44a201983d914578

Reproduction Steps

reproduction steps
# prerequisites

mkdiff oneoff
cd oneoff
npm init -y -f
npm i -S @apollo/server @apollo/gateway @apollo/subgraph

cat  > subgraph.mjs << 'EOT'
import { ApolloServer } from '@apollo/server'
import { startStandaloneServer } from '@apollo/server/standalone'
import { parse } from 'graphql'
import { buildSubgraphSchema } from '@apollo/subgraph' // added for federation

const typeDefs = parse(`#graphql
  directive @oneOf on INPUT_OBJECT

  type Query {
    users(where: UserWhere!): [User!]!
  }

  type User {
    id: ID!
    username: String
  }

  input UserWhere @oneOf {
    foo: Int
    bar: Int
  }
`)

const resolvers = {
  Query: {
    users: () => [{ id: '1', username: '@mac' }],
  },
}

const server = new ApolloServer({
  schema: buildSubgraphSchema({ typeDefs, resolvers }), // federated graphql server, instead of `typeDefs, resolvers`
})
startStandaloneServer(server).then(({ url }) => console.log(`open ${url}`))
EOT

cat  > supergraph.mjs << 'EOT'
import { ApolloServer } from '@apollo/server'
import { ApolloGateway, IntrospectAndCompose } from '@apollo/gateway'
import { startStandaloneServer } from '@apollo/server/standalone'

const gateway = new ApolloGateway({
  supergraphSdl: new IntrospectAndCompose({
    subgraphs: [{ name: 'demo', url: 'http://localhost:4000' }],
  }),
})

const server = new ApolloServer({ gateway })
startStandaloneServer(server, { listen: { port: 3000 } }).then(({ url }) => console.log(`open ${url}`))
EOT

# reproduction

# start the server
node subgraph.mjs
# check if we can receive isOneOf - should respond with true
curl -s -X POST http://localhost:4000 -H 'content-type: application/json' -d '{"query":"{ __type(name: \"UserWhere\") { name isOneOf } }"}' | jq .data.__type.isOneOf

# start gateway
node supergraph.mjs
# the same check - but for gateway
curl -s -X POST http://localhost:3000 -H 'content-type: application/json' -d '{"query":"{ __type(name: \"UserWhere\") { name isOneOf } }"}' | jq
# will fail with error: Cannot query field "isOneOf" on type "__Type".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant