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

federation: resolveType of extended interface without knowledge of concrete type #377

Open
cmschuetz opened this issue Aug 15, 2019 · 3 comments

Comments

@cmschuetz
Copy link
Contributor

Our existing services and clients utilize the node interface for object resolution and I haven't been able to figure out a way to implement this with federation

Given the following services:

Product Service

const typeDefs = gql`
  interface Node {
    id: ID!
  }

  type Product implements Node @key(fields: "id") {
    id: ID!
    status: String
  }
`

const resolvers = {
  Product: {
    __resolveReference({ id }) {
      return { id, status: 'in_stock' }
    },
  },
}

Node Resolution Service

const typeDefs = gql`
  interface Node @key(fields: "id") @extends {
    id: ID! @external
  }

  extend type Query {
    node(id: ID!): Node
  }
`

const resolvers = {
  Node: {
    __resolveType(object) {
      return object.__typename
    },
  },
  Query: {
    node(_, args) {
      const [__typename, decodedId] = Base64.decode(args.id).split('-')
      return { __typename, id: decodedId }
    },
  },
}

I am unable to lookup a product via the node field with its encoded id. Intuitively, this makes sense because the node resolution service is unaware of any types returned from __resolveType. How feasible would it be for __resolveType to allow for arbitrary types if it's extended?

Or am I thinking about this problem in the wrong way - have there been any other ideas for implementing the node interface with federation and gateway?

@victorandree
Copy link

I've thought a bit about this problem, too. Here's my 2 cents.

Federated service should still work standalone, which your Node resolution service cannot possibly do. This is because its schema doesn't have any types for the Node interface. For it to run as a standalone service, it should contain all the possible types of Node, marking them all as extend type Product. I.e., your Node resolution service would then be:

const typeDefs = gql`
  interface Node @key(fields: "id") @extends {
    id: ID! @external
  }

  type Product @key(fields: "id") @extends {
    id: ID! @external
  }

  extend type Query {
    node(id: ID!): Node
  }
`

const resolvers = {
  Node: {
    __resolveType(object) {
      return object.__typename
    },
  },
  Query: {
    node(_, args) {
      const [__typename, decodedId] = Base64.decode(args.id).split('-')
      return { __typename, id: decodedId }
    },
  },
}

However, this will mean that your Node resolution service must know of every type, and that it will resolve nodes which might not exist. The latter may be considered a feature, the former leads me to thinking that Node resolution should be part of the gateway (which anyway knows of every type). To my knowledge, there's no support for schemas which are only part of the gateway.

You should be able to construct your Node resolution service as a service in the gateway, though. For example, you can extend ApolloGateway to override loadServiceDefinitions or createSchema. Once all other services are loaded, it should be possible to dynamically create the Node resolution service in the gateway only.

@victorandree
Copy link

Minimal working example: https://github.com/victorandree/apollo-federation-relay (see TODO)

@abernix abernix transferred this issue from apollographql/apollo-server Jan 15, 2021
@tot-ra
Copy link

tot-ra commented Oct 10, 2021

Thanks a lot, this example helped.

@queerviolet any chance to have node query supported be moved into apollo server natively to avoid extra network hop just to resolve references?

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

4 participants