Interfaces
The bookshop starts selling magazines. A magazine has an ID, a title and a price, just like a book, but no author: it has an issue number instead. The home page wants one "new arrivals" list mixing both. An interface lets one field return either, while guaranteeing the fields they share.
The rule
An interface promises shared fields; ask for extras with
... on Type.
Declare the shared fields once, then have each object type implement the interface:
interface Product {
id: ID!
title: String!
price: Float!
}
type Book implements Product {
id: ID!
title: String!
price: Float!
author: Author!
}
type Magazine implements Product {
id: ID!
title: String!
price: Float!
issue: Int!
}
type Query {
newArrivals(first: Int = 10): [Product!]!
}The rules for implementing:
- A type must include every field of the interface, with the same arguments and a compatible type (the same type, or a stricter one such as
String!forString). - It may add fields of its own, like
authororissue. - A type can implement several interfaces:
type Book implements Product & Node.
When a field returns an interface, you can select the shared fields directly. For type-specific fields, use an inline fragment with a type condition, and add __typename so the client knows what each item is:
{
newArrivals {
__typename
title
price
... on Book { author { name } }
... on Magazine { issue }
}
}{ "data": { "newArrivals": [
{ "__typename": "Book", "title": "The Salt Road", "price": 499, "author": { "name": "Mira Kapoor" } },
{ "__typename": "Magazine", "title": "Readers Monthly", "price": 120, "issue": 42 }
] } }On the server, the interface needs one extra piece of code: a way to tell, for each value, which concrete type it is (often called resolveType).
The shortcut
For every field you want from an interface-typed result, ask "is it on the interface?" Yes → select it directly. No → put it inside ... on ConcreteType.
Shared fields
titleandpriceare onProduct: select them directly.
The usual error is selecting a concrete type's field directly on the interface, such as newArrivals { issue }. The server rejects it, because Product has no issue.
Drills
Answer fast — trust the rule.
Why is { newArrivals { title issue } } rejected?
Magazine implements Product but leaves out price. What happens?
For a Magazine item, what does ... on Book { author { name } } add to the result?
How does the client know whether each item in newArrivals is a book or a magazine?
Remember
- An interface promises shared fields; ask for extras with
... on Type. - Is the field on the interface? Select it directly. If not, use an inline fragment.
- Trap: implementing types must include every interface field, and concrete fields cannot be selected on the interface.
