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

Specify the behavior of @override #65

Open
kamilkisiela opened this issue Dec 11, 2024 · 1 comment
Open

Specify the behavior of @override #65

kamilkisiela opened this issue Dec 11, 2024 · 1 comment

Comments

@kamilkisiela
Copy link

kamilkisiela commented Dec 11, 2024

Since we have @override in the spec I wanted us to define its behavior a bit.

In Apollo Federation, the definition of the is:

@override indicates that an object field is now resolved by this subgraph instead of another subgraph where it’s also defined.

Here’s a simple example, but I will dive deeper soon :)

# subgraph A

type User @key(fields: "id") {
  id: ID!
  profile: Profile @shareable @override(from: "b")
}

type Profile @key(fields: "id") {
  id: ID!
  bio: String!
}

# subgraph B

type Query {
  user: User
}

type User @key(fields: "id") {
  id: ID!
  profile: Profile @shareable
}

type Profile @key(fields: "id") {
  id: ID!
  bio: String!
}

To my understanding, every time (in this situation where there are two subgraphs) when a gateway asks for User.profile it has to be resolved by subgraph A.

When I query:

query {
  user {             # resolved by B
    profile {        # resolved by A
      bio            # resolved by A
    }
  }
}

This one is easy, so let’s complicate it a bit by adding an entity on top of it all and @provides directive.

# Subgraph A

type Dashboard @key(fields: "id") {
  id: ID
  user: User @shareable
}

type User @key(fields: "id") {
  id: ID!
  profile: Profile @override(from: "b")
}

type Profile @key(fields: "id") {
  id: ID!
  name: String! @shareable
  bio: String @shareable
}

# Subgraph B

type Query {
  dashboard: Dashboard
}

type Dashboard @key(fields: "id") {
  id: ID
  user: User @shareable @provides(fields: "profile { bio }")
}

type User @key(fields: "id") {
  id: ID!
  profile: Profile
}

type Profile @key(fields: "id") {
  id: ID!
  name: String! @shareable
  bio: String @external
}

And at this point I have two questions.
Should @override on User.profile be ignored if provided fields (see @provides) can resolve the { user { profile { bio } } } part of the query?

query {
  dashboard {        # B
    user {           # B
      profile {      # B, but should it be B?
        bio          # B
      }
    }
  }
}

In my opinion, if we allow to bypass @override when a query path matches @provides(fields:) then we should be very specific about it and describe this behavior well in the spec.

The next question, but more obvious is what should happen when a user requests Profile.id as well, or Profile.name, so instead of profile { bio } there’s profile { bio id name }.

I checked how gateways are handling it (for the audit I did) and all of them are not following any rules consistently.

@kamilkisiela
Copy link
Author

kamilkisiela commented Dec 11, 2024

My take here is that we should either say

every time an overridden field is to be resolved, use the overriding subgraph instead

or

treat overridden field as @external, but if it is to be resolved directly (not through a query path with @provides), used the overriding subgraph instead

Because if we treat it only as @external, then the definition from Apollo Federation docs that I mentioned in the issue:

@override indicates that an object field is now resolved by this subgraph instead of another subgraph where it’s also defined.

is no longer true when there are more subgraphs defining that field.

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