6. Building a schema


Time to level up from "Hello world" to "Hello playlists"!

In this lesson, we will:

  • Examine a mockup design and create a from it
  • Create our first
  • Learn how to a with the [GraphQLDescription] attribute

The mockup

To kick things off, let's take a look at this page from the MusicMatcher app:

A grid of featured playlists

It showcases a grid of featured popular playlists that you may be interested in!

Breaking each playlist down, we can start to see what pieces of data the client app will need. This process of breaking down a mockup to pieces of data is called schema-first design.

The same mockup but with labels for each piece of data

A playlist needs a name and a description, which are both pieces of text.

Even though we're not implementing the schema-first approach in Hot Chocolate (that is, we're not writing the schema in ), it's still helpful to think about what types and our functions will be defining based on the mockup designs and data that the app developers expect.

The Playlist type

Let's start with the Playlist type. In the Types folder, create a new class called Playlist.

namespace Odyssey.MusicMatcher;
public class Playlist
// Playlist properties go here

Inside the Playlist class, we'll start by defining the name of our playlist as a property, which returns a string type.

public string Name { get; set; }

By default, this is non-nullable, so a playlist requires a name.

Note: We're using the short-hand syntax for auto-implemented properties.

Right now, we'll get a yellow squiggly line under "Name" and a warning saying:

Non-nullable property 'Name' must contain a non-null value when exiting constructor.
Consider declaring the property as nullable.

Don't worry, we'll address that in a bit.

Next, let's define the playlist's description, which is also a string type. A description can be null, so we'll mark it as such using the ? symbol.

public string? Description { get; set; }

One more thing! Even though it wasn't part of the mockup, it's common practice to also define an identifier for a class. Looking ahead, when we click into a playlist, we'll need to have a way to retrieve the details for that specific playlist, and that's exactly what the identifier (or ID) is for.

The ID for a playlist will be a string type, but we want to map it to a type for ID, not String. To do this, we'll add the Hot Chocolate attribute [ID].

public string Id { get; }

We're using the [ID] attribute from the Relay spec because it is a commonly used pattern in and the [ID] attribute is simpler in our code. To use the proper Hot Chocolate types, we could replace [ID] with [GraphQLType(typeof(IdType))].

We've also omitted the set; method here because we typically don't want the ID to be changed.

The three properties we've defined for a playlist (Id, Name and Description) act as the resolvers for those . Behind the scenes, Hot Chocolate converts each property with a get accessor to a .

Exploring the schema

What does this Playlist class look like in our now? Let's find out!

We'll need to register the Playlist class with our , so open up the Program.cs file and find where we initialized the server.

We'll chain another method called AddType and pass in the Playlist.


Save all our changes and restart the server.

Back to Sandbox, let's check out the Schema page. Select Objects on the left-hand side and click Playlist.


Sandbox showing Schema Reference and Objects selected

Awesome, we've accounted for all the playlist !


Sandbox showing Playlist schema

Right now, the details column shows "No description". Although the names feel fairly self-explanatory right now, it's good practice to the types and fields of your schema, especially for consumers of our .

Documenting our schema

We use descriptions to a schema. (Not to be confused with our playlist's description field!) In Hot Chocolate, we use the [GraphQLDescription] attribute, which takes a string as an that describes the type or .

Back to our Playlist class, let's add the [GraphQLDescription] just above the class definitions and the properties.

[GraphQLDescription("A curated collection of tracks designed for a specific activity or mood.")]
public class Playlist
[GraphQLDescription("The ID for the playlist.")]
public string Id { get; }
[GraphQLDescription("The name of the playlist.")]
public string Name { get; set; }
[GraphQLDescription("Describes the playlist, what to expect and entices the user to listen.")]
public string? Description { get; set; }

Save our changes, restart the server and switch over to Sandbox to see our clear and helpful descriptions!


Sandbox showing Playlist schema with descriptions

The Playlist constructor

We've still got some yellow squiggly lines and warnings in our Playlist class (two now!), so let's fix those.

We'll create a constructor for the class, passing in id and name . We can leave description alone since it's nullable.

public Playlist(string id, string name)
Id = id;
Name = name;

We'll use these to create instances of the Playlist class in the next lesson.


What is the [ID] attribute used for on the Id property in the Playlist class?
Which of the following statements are true about schema documentation?
In Apollo Sandbox, what page would you navigate to for a detailed reference to your GraphQL schema?
Code Challenge!

Create an Artist class that produces a GraphQL type with the following fields: id: ID!, name: String!, followers: Int and popularity: Float. Note the types for each field and their nullability.

Loading progress

Key takeaways

  • Breaking down a mockup into data pieces and implementing features based on client application needs is known as schema-first design.
  • The [GraphQLDescription] attribute is used to add clear and helpful descriptions to types and . It will be displayed in GraphQL IDEs such as .
  • The [ID] attribute defines the identifier for the type. It indicates that the associated property represents a unique identifier.

Up next

We need a way to for a playlist. Right now, it's just floating in our schema without a way to access it. Let's make it available through our Query type — our entry point to the schema!


Share your questions and comments about this lesson

This course is currently in

. Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.