Introduction to Interfaces
In GraphQL, interfaces are a powerful way to define a set of fields that multiple types can implement. This allows for more flexible and reusable schemas. Interfaces help in creating a polymorphic schema where different types can be queried through a common interface.
Key Concepts
- Interface Definition: An interface defines a set of fields that a type must include.
- Type Implementation: Types that implement an interface must include the fields defined by the interface.
- Querying Interfaces: You can query fields on an interface and get results from any type that implements the interface.
Defining Interfaces
To define an interface in GraphQL, you use the interface keyword followed by the name of the interface and the fields it includes.
In this example, the Character interface includes three fields: id, name, and friends.
Implementing Interfaces
Types that implement an interface must include all the fields defined by the interface. Here’s how you can define types that implement the Character interface:
type Human implements Character {
id: ID!
name: String!
friends: [Character]
homePlanet: String
}
type Droid implements Character {
id: ID!
name: String!
friends: [Character]
primaryFunction: String
}In this example, both Human and Droid types implement the Character interface. They include the id, name, and friends fields, and also have their own specific fields (homePlanet for Human and primaryFunction for Droid).
Querying Interfaces
When querying an interface, you can request fields that are common to all types implementing the interface. You can also use inline fragments to request fields specific to a particular type.
In this query, characters is a field that returns a list of Character interface types. The query requests the id and name fields (common to all Character types) and uses inline fragments to request homePlanet for Human and primaryFunction for Droid.
Practical Example
Let's create a simple GraphQL schema with an interface and types implementing it.
Schema Definition
interface Character {
id: ID!
name: String!
friends: [Character]
}
type Human implements Character {
id: ID!
name: String!
friends: [Character]
homePlanet: String
}
type Droid implements Character {
id: ID!
name: String!
friends: [Character]
primaryFunction: String
}
type Query {
characters: [Character]
}Resolvers
const resolvers = {
Query: {
characters: () => [
{ id: '1', name: 'Luke Skywalker', homePlanet: 'Tatooine', friends: [], __typename: 'Human' },
{ id: '2', name: 'R2-D2', primaryFunction: 'Astromech', friends: [], __typename: 'Droid' }
]
},
Character: {
__resolveType(character) {
if (character.homePlanet) {
return 'Human';
}
if (character.primaryFunction) {
return 'Droid';
}
return null;
}
}
};In this example, the __resolveType function is used to determine the type of a Character at runtime.
Exercises
Exercise 1: Define an Interface
Define an interface Vehicle with the fields id, name, and speed.
Solution
Exercise 2: Implement the Interface
Create two types, Car and Bike, that implement the Vehicle interface. Add a specific field numWheels to Car and type to Bike.
Solution
type Car implements Vehicle {
id: ID!
name: String!
speed: Int!
numWheels: Int!
}
type Bike implements Vehicle {
id: ID!
name: String!
speed: Int!
type: String!
}Exercise 3: Query the Interface
Write a query to fetch id, name, and speed for all vehicles, and also fetch numWheels for Car and type for Bike.
Solution
Conclusion
Interfaces in GraphQL provide a way to define a set of fields that multiple types can implement, allowing for more flexible and reusable schemas. By understanding how to define, implement, and query interfaces, you can create more powerful and maintainable GraphQL APIs. In the next topic, we will explore Unions, which offer another way to handle polymorphic types in GraphQL.
