GraphQL Sufferfest: Nested Types
I've been working on a side project as a means to bone up on React and GraphQL. GraphQL in particular has been a struggle. Coming from the world of trad REST endpoints, GraphQL's paradigm seems powerful but it's also a bit of a mindfuck.
This is not a general GraphQL tutorial. This is about working with nested objects (or nested types, in GraphQL parlance). If you don't know what GraphQL is, probably go somewhere else first. When you get to a point where you need a nested type, come back. I'll be here.
Why Nested Types
For any real world application API the data a consumer is going to need are going to have complexity. Objects will, at some point, have their own nested objects within them.
Think of an events management app for example. Your API needs to return events and whatever goes along with them. An event itself is complex, it probably has a name, a date/time and maybe a venue. A venue probably has it's own properties right? At least a name and a location.
The venue sounds like a nested type within an event.
To query and update (mutate) nested objects like these venues they need to have inputs and types defined for them within your GraphQL schema just like the parent object (the event) does.
My Project
I'm building browser based drum machine/synth using GraphQL for an API that can save and retrieve compositions written with it.
A composition has a name and some other irrelevant to this article shit. What is relevant are the instruments that make up a composition. In my case, say you write a drum beat... This composition might be made up of hits for a snare, a kick and a high hat. Three instruments, represented in an array for any composition.
These instruments are objects themselves each with their own music, that our beloved user wrote. The music itself is an array of booleans.
An instrument sounds like a nested type to me. Let's have at it with the code.
The Schema
Here's the entire schema for this friggin' app.
const { buildSchema } = require('graphql')
const schema = buildSchema(`
type Composition {
_id: ID!
title: String!
musicList: [IndividualInstrumentMusic!]!
}
input CompositionInput {
music: [IndividualInstrumentMusic!]!
}
type IndividualInstrumentMusicType {
instrumentName: String!
music: [String!]!
}
input IndividualInstrumentMusicInput {
instrument: String!
music: [String!]!
}
type Query {
compositions: [Composition!]!
}
type Mutation {
createComposition(compositionInput: CompositionInput): Composition
}
schema {
query: Query
mutation: Mutation
}
`)
module.exports = schema
So this schema defines compositions that each have an array of the terribly named InvidualInstrmentMusic
objects. Our nested types.
You'll notice that we've got a separately defined type
(IndividualInstrumentMusicType
) and input
(IndividualInstrumentMusicInput
) for mutations.
A Query
One that returns all of the compositions in the database.
const query = `{
compositions {
title
musicList {
instrumentName
music
}
}
}`
Notice that we need to define what we want out of the nested objects in the musicList
as well.
A Mutation
One that returns the composition title and the music that was created:
const mutation = `mutation {
createComposition(
compositionInput: {
title: "Concerto Number 666",
recording:[{ instrumentName: "snare", music: [true, false, true] }]
}
){
title
musicList {
instrumentName
music
}
}
}`
Notice again that we are defining what we want back for our music list... The specific fields for these nested types.
That's it. This is all in the GraphQL documentation but I'm bad at reading that stuff so it took a lot of suffering to figure this out.
The upside is that I learned it real well.
Enjoy! <3