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.