Leveraging Interfaces in GraphQL Schema Design
By: Ryan Kanner @CodeProKid
©2020 Copyright - Confidential and Proprietary
About Me
-
Live in Denver, CO
-
Engineer on the Content Platform / WordPress team @ NerdWallet
-
Co-organizer of GraphQL & WordPress meetups in Denver
-
Help maintain WPGraphQL, an open source project bringing GraphQL to WordPress
-
Crazy dog, Blake
-
Baseball Fan
... I also love Pizza
©2020 Copyright - Confidential and Proprietary
In another lifetime
©2020 Copyright - Confidential and Proprietary
Killing the Pizza Game
©2020 Copyright - Confidential and Proprietary
A Perfect Combination
©2020 Copyright - Confidential and Proprietary
+
=
©2020 Copyright - Confidential and Proprietary
Specials Board
query {
specials: [Pizza]
}
type Pizza {
id: ID!
image: String
name: String!
sauce: String
cheese: String
toppings: [String]
price: Float!
}
©2020 Copyright - Confidential and Proprietary
Updated Specials Board
type Pizza {
id: ID!
image: String
name: String!
sauce: String
cheese: String
toppings: [String]
price: Float!
}
type Side {
id: ID!
image: String
name: String!
sauce: String
cheese: String
quantity: Int
price: Float!
}
interface FoodItem {
id: ID!
image: String
name: String!
sauce: String
cheese: String
price: Float!
}
query {
specials: [FoodItem!]
}
So, What are Interfaces?
©2020 Copyright - Confidential and Proprietary
An Interface is an abstract type that includes a certain set of fields that a type must include to implement the interface
interface FoodItem {
id: ID!
name: String!
price: Float!
image: String
sauce: String
cheese: String
}
©2020 Copyright - Confidential and Proprietary
type Pizza implements FoodItem {
id: ID!
name: String!
price: Float!
image: String
sauce: String
cheese: String
toppings: [String!]
}
type Side implements FoodItem {
id: ID!
name: String!
price: Float!
image: String
sauce: String
cheese: String
quantity: Int
}
Querying Interfaces
©2020 Copyright - Confidential and Proprietary
query FEATURED_ITEMS {
specials {
__typename
id
name
image
price
sauce
cheese
... on Pizza {
toppings
}
... on Side {
quantity
}
}
}
type Query {
specials: [FoodItem!]
}
interface FoodItem {
id: ID!
name: String!
price: Float!
image: String
sauce: String
cheese: String
}
type Pizza implements FoodItem {
...
toppings: [String]
}
type Side implements FoodItem {
...
quantity: Int
}
What about unions?
©2020 Copyright - Confidential and Proprietary
type Query {
specials: [FoodItem!]
}
union FoodItem = Pizza | Side
type Pizza {
id: ID!
name: String!
price: Float!
image: String
sauce: String
cheese: String
crust: String
}
type Side {
id: ID!
name: String!
price: Float!
image: String
sauce: String
cheese: String
quantity: Int
}
query FOOD_ITEM_UNION {
specials {
__typename
... on Pizza {
id
name
price
image
sauce
cheese
crust
}
... on Side {
id
name
price
image
sauce
cheese
quantity
}
}
}
The difference visualized
©2020 Copyright - Confidential and Proprietary
FoodItem
- id
- name
- price
- image
- sauce
- cheese
Pizza
- toppings
Side
- quantity
FoodItem
Pizza
- id
- name
- price
- image
- sauce
- cheese
- toppings
Side
- id
- name
- price
- image
- sauce
- cheese
- quantity
Interfaces
Unions
What about something a little more complex?
©2020 Copyright - Confidential and Proprietary
©2020 Copyright - Confidential and Proprietary
Another change to the specials
type Pizza {
id: ID!
image: String
name: String!
price: Float!
sauce: String
cheese: String
toppings: [String]
}
type Side {
id: ID!
image: String
name: String!
price: Float!
sauce: String
cheese: String
quantity: Int
}
type Apparel {
id: ID!
image: String
name: String!
price: Float!
inStock: Boolean!
description: String
}
Multiple Interfaces
©2020 Copyright - Confidential and Proprietary
interface FoodItem {
sauce: String
cheese: String
}
type Apparel implements
Product {
id: ID!
name: String!
price: Float!
image: String
inStock: Boolean!
description: String
}
interface Product {
id: ID!
name: String!
price: Float!
image: String
}
type Pizza implements
FoodItem & Product {
id: ID!
name: String!
price: Float!
image: String
sauce: String
cheese: String
toppings: [String]
}
type Side implements
FoodItem & Product {
id: ID!
name: String!
price: Float!
image: String
sauce: String
cheese: String
quantity: Int
}
Multiple Interfaces Query
©2020 Copyright - Confidential and Proprietary
type Query {
specials: [Product!]
}
query FEATURED_ITEMS {
specials {
__typename
id
name
image
price
... on FoodItem {
sauce
cheese
}
... on Pizza {
toppings
}
... on Side {
quantity
}
... on Apparel {
inStock
description
}
}
}
Pizza
Apparel
Side
Component Mappings
©2020 Copyright - Confidential and Proprietary
<ProductCard>
fragment pf on Product {
__typename
id
name
price
image
... foodFields
... apparelFields
}
<FoodItemDetails>
fragment foodFields
on FoodItem {
__typename
sauce
cheese
... on Pizza {
toppings
}
... on Side {
quantity
dippingSauce: sauce
}
}
<ApparelDetails>
fragment apparelFields
on Apparel {
inStock
description
}
©2020 Copyright - Confidential and Proprietary
Multiple DataType Handling Without GraphQL
Pizza
GET /api/v99/pizza/1
Apparel
GET /api/v99/apparel/2
Side
GET /api/v99/side/3
Takeaways
©2020 Copyright - Confidential and Proprietary
- Interfaces help bring your Type's together, and make your Graph more flexible.
- Make your components more re-usable.
- Using multiple interfaces with Types can unlock powerful Query combinations.
- A tradeoff of using interfaces is that you have to code defensively on the client.
- PizzaQL 4 Life.
Thanks for coming! Questions?
©2020 Copyright - Confidential and Proprietary
Leveraging Interfaces in GraphQL Schema Design
By Ryan Kanner
Leveraging Interfaces in GraphQL Schema Design
- 1,186