# Heirarchical

> Most product development today involves the creation and manipulation of view hierarchies. To achieve congruence with 
the structure of these applications, a GraphQL query itself is structured hierarchically. The query is shaped just like 
the data it returns. It is a natural way for clients to describe data requirements.

See the [GraphQL specification](https://spec.graphql.org/June2018/) for more details.

How might we apply this principle? Consider if you were to design a GraphQL type `Song` which has an associated 
`Artist` and `Product` (the reality is much more complicated). One way to model this would be to return the data as it 
appears from the database. For example, we may have a Sound Recording SQL table in MySQL that resembles something like:

```
| isrc         | name           | fk_artist_id | fk_product_id |
|--------------|----------------|--------------|---------------|
| QM4TW2003053 | Hold Your Hand | 1465654      | 2761914       |
| QM4TW2003054 | Beg Me         | 1465654      | 2761914       |
| QM4TW2003060 | Options        | 1465654      | 2761914       |
``` 

This could, in turn, be returned from a microservice payload as something like:

```url
GET /song?isrc=QM4TW2003053,QM4TW2003054,QM4TW2003060
Content-Type: application/json
```

```json[
    {
        "isrc": "QM4TW2003053",
        "name": "Hold Your Hand",
        "artist_id": 1465654,
        "product_id": 2761914
    },
    {
        "isrc": "QM4TW2003054",
        "name": "Beg Me",
        "artist_id": 1465654,
        "product_id": 2761914
    },
    {
        "isrc": "QM4TW2003060",
        "name": "Options",
        "artist_id": 1465654,
        "product_id": 2761914
    }
]
```

One way to model this data in a GraphQL type could be to return the data as-is:

```graphql
type Song {
    isrc: ID!
    name: String!
    artistId: ID!
    productId: ID!
}
```

On your frontend, you could display this in a React component as:

```jsx
const SongList = songs => (
    <ul>
        {
            songs.map(({ isrc, name }) => (
                <li>
                    <a href={`song/${isrc}`}>{name}</a>
                </li>
            ))
        }
    </ul>
);
```

Now let's assume that we now have to render the artist's name as well. We could amend our SQL query to join on an
Artist table, and return the artist name in the JSON payload:

```url
GET /song?isrc=QM4TW2003053,QM4TW2003054,QM4TW2003060
Content-Type: application/json
```

```json[
    {
        "isrc": "QM4TW2003053",
        "name": "Hold Your Hand",
        "artist_id": 1465654,
        "artist_name": "Myrna",
        "product_id": 2761914
    },
    {
        "isrc": "QM4TW2003054",
        "name": "Beg Me",
        "artist_id": 1465654,
        "artist_name": "Myrna",
        "product_id": 2761914
    },
    {
        "isrc": "QM4TW2003060",
        "name": "Options",
        "artist_id": 1465654,
        "artist_name": "Myrna",
        "product_id": 2761914
    }
]
```

and then add an `aritstName` field to our `Song` type:

```graphql
type Song {
    isrc: ID!
    name: String!
    artistId: ID!
    artistName: String!
    productId: ID!
}
```

```jsx
const SongList = songs => (
    <ul>
        {
            songs.map(({ isrc, name, artistName }) => (
                <li>
                    <a href={`song/${isrc}`}>`${name} - ${artistName}`</a>
                </li>
            ))
        }
    </ul>
);
```

This is fine for our current feature, but becomes increasingly more difficult to model once the frontend requires more
and more information about artists. For example, suppose a subsequent requirement is to include the artist's Spotify id
to link to their artist page, and a count of their Spotify monthly listeners. We could keep adding to the `Song` type:

```graphql
type Song {
    isrc: ID!
    name: String!
    artistId: ID!
    artistName: String!
    artistSpotifyId: ID!
    artistSpotifyMonthlyListeners: Long!
    productId: ID!
}
```

but this will become increasingly more complex as we add more and more information to the `Song` model. Besides, these
are attributes of an `Artist`, and not necessarily attributes of the `Song` itself. How could we have avoided this?

If our schema is designed hierarchically, we can append attributes to our `Artist` type:

```graphql
type Song {
    isrc: ID!
    name: String!
    artist: Artist!
    productId: ID!
}

type Artist {
    id: ID!
    name: String!
    spotifyId: ID!
    spotifyMonthlyListeners: Long!
}
```

It's also possible that we're now seeing that Spotify data itself should be another `type`. This might be useful, so 
it's important to put quite a bit of forethought into designing a GraphQL schema that supports these types of 
relationships.