Skip to content

GAP-55 @fetchable Identity#55

Open
mjmahone wants to merge 6 commits into
graphql:mainfrom
mjmahone:mjmahone-fetchable
Open

GAP-55 @fetchable Identity#55
mjmahone wants to merge 6 commits into
graphql:mainfrom
mjmahone:mjmahone-fetchable

Conversation

@mjmahone

@mjmahone mjmahone commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

How we use @fetchable to indicate identity internally at Meta. Works in conjunction with the @strong specification. #54

@mjmahone mjmahone changed the title Draft Identity GAP: @fetchable Identity GAP: @fetchable Jun 9, 2026
@mjmahone mjmahone changed the title Identity GAP: @fetchable GAP-55 @fetchable Identity Jun 9, 2026
@mjmahone mjmahone self-assigned this Jun 10, 2026
Comment thread gaps/GAP-55/DRAFT.md
for identity while a separate, larger token field is required to fetch the
object.

## Generated root fields

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an interface that is @fetchable, what are its generated fields? Are the root fields generated for only the concrete types, or for the interface as well?

Using your example above for Story, is fetch__Story(id:) available or just fetch__PhotoStory(id:)?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realized this is in the README. Should it be included here as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably!

But yes: each type (Object or Interface) that is @fetchable gets its own Query fields.

This is important: you may need the identity for interface fetchability to encode the underlying type, to make resolving across a cloud of types efficient, whereas the default fetchable field for a given object could be its standard @strong field.

Comment thread gaps/GAP-55/DRAFT.md
`field_name` is required on an `@fetchable` interface, just as it is on an
`@fetchable` object. All types implementing an `@fetchable` interface must
themselves be `@fetchable`, but the interface and its implementations each
specify their own `field_name` and _need not_ share the same value.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused by this section. If field_name is required on all @fetchable interfaces, but each type can specify their own field_name, how does it extend the interface correctly?

Here is an example that seems like it would be valid according to this section:

# "field_name" is required, so it needs to be provided with
# a value
interface Story @fetchable(field_name: "id") {
  id: ID!
}

# field_name can be different than its interface
type PhotoStory implements Story @fetchable(field_name: "cache_id") {
  # id required by the interface
  id: ID!
  cache_id: ID!
}

Am I understanding this correctly? If so, what is the value in having different @fetchable field names?

This ties into the question for generated root fields. If root fields are only generated for object types, why is field_name required for @fetchable interfaces?

Clarification on my misunderstand would be helpful 🙂

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realized this is included in the README. Should it be mentioned here as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if root fields are only generated for object types,

not just object types

Comment thread gaps/GAP-55/README.md
}

type Query {
fetch__Animal(id: ID!): Animal

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would a client know to use this field since it only knows about concrete types? (e.g. __typename will never be Animal).

@mjmahone mjmahone Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client knows it is requesting an interface: the random_animal field returns an Animal therefore the client can know to use the fetch__Animal root field.

This may require manually knowing if there is no compiler to automatically thread these through. We always have a compiler step for producing queries for any client with a store, so this is not a problem for us. Alternatively, you could use the __fulfilled meta-field (@s3wasser may have a GAP coming to describe this, though we've described it in different PRs in the past: https://rfcs.graphql.org/rfcs/879/) to answer which specific interfaces were asked for.

@mjmahone mjmahone Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also just logistically: we recommend against using __typename for any amount of business logic. The only thing we sometimes feel forced into using the explicitly returned-from-the-server __typename field for is creating a globally unique key for our client store out of a per-type key. Using it for "is this spread fulfilled" is in our opinion a bad practice, see: https://graphql.org/conf/2026/schedule/7d3a7e26a24ad1ef28c0c9a913dd69bb/?name=The%20Case%20Against%20__typename%20-%20Sabrina%20Wasserman,%20Meta%20Platforms%20Inc

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the "Apollo Client" way of thinking is so engrained in me which is why I have a hard time thinking about how these fit together, especially the lack of schema knowledge or compiler to help on that end of things. Thanks for the clarification!

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

Successfully merging this pull request may close these issues.

2 participants