GraphQL types
GraphQL supports many different types. As you saw in the previous section, types define the shape or behavior of your data. They are the fundamental building blocks of a GraphQL schema.
Types can be categorized into inputs and outputs. Inputs are types that are allowed to be passed in as
the argument for the special object types (Query
, Mutation
, etc.), whereas
output types are strictly used to store and return data. A list of types and their categorizations are
listed below:
-
Objects: An object contains fields describing an entity. For instance, an object could be something like a
book
with fields describing its characteristics likeauthorName
,publishingYear
, etc. They are strictly output types. -
Scalars: These are primitive types like int, string, etc. They are typically assigned to fields. Using the
authorName
field as an example, it could be assigned theString
scalar to store a name like "John Smith". Scalars can be both input and output types. -
Inputs: Inputs allow you to pass a group of fields as an argument. They are structured very similarly to objects, but they can be passed in as arguments to special objects. Inputs allow you to define scalars, enums, and other inputs in its scope. Inputs can only be input types.
-
Special objects: Special objects perform state-changing operations and do the bulk of the heavy lifting of the service. There are three special object types: query, mutation, and subscription. Queries typically fetch data; mutations manipulate data; subscriptions open and maintain a two-way connection between clients and servers for constant communication. Special objects are neither input nor output given their functionality.
-
Enums: Enums are predefined lists of legal values. If you call an enum, its values can only be what's defined in its scope. For example, if you had an enum called
trafficLights
depicting a list of traffic signals, it could have values likeredLight
andgreenLight
but notpurpleLight
. A real traffic light will only have so many signals, so you could use the enum to define them and force them to be the only legal values when referencingtrafficLight
. Enums can be both input and output types. -
Unions/interfaces: Unions allow you to return one or more things in a request depending on the data that was requested by the client. For example, if you had a
Book
type with atitle
field and anAuthor
type with aname
field, you could create a union between both types. If your client wanted to query a database for the phrase "Julius Caesar", the union could return Julius Caesar (the play by William Shakespeare) from theBook
title
and Julius Caesar (the author of Commentarii de Bello Gallico) from theAuthor
name
. Unions can only be output types.Interfaces are sets of fields that objects must implement. This is a bit similar to interfaces in programming languages like Java where you must implement the fields defined in the interface. For example, let's say you made an interface called
Book
that contained atitle
field. Let's say you later created a type calledNovel
that implementedBook
. YourNovel
would have to include atitle
field. However, yourNovel
could also include other fields not in the interface likepageCount
orISBN
. Interfaces can only be output types.
The following sections will explain how each type works in GraphQL.
Objects
GraphQL objects are the main type you will see in production code. In GraphQL, you can think of an object as a grouping of different fields (similar to variables in other languages), with each field being defined by a type (typically a scalar or another object) that can hold a value. Objects represent a unit of data that can be retrieved/manipulated from your service implementation.
Object types are declared using the Type
keyword. Let's modify our schema example
slightly:
type Person { id: ID! name: String age: Int occupation: Occupation } type Occupation { title: String }
The object types here are Person
and Occupation
. Each object has its own
fields with its own types. One feature of GraphQL is the ability to set fields to other types. You can
see the occupation
field in Person
contains an Occupation
object type. We can make this association because GraphQL is only describing the data and not the
implementation of the service.
Scalars
Scalars are essentially primitive types that hold values. In AWS AppSync, there are two types of
scalars: the default GraphQL scalars and AWS AppSync scalars. Scalars are typically used to store field
values within object types. Default GraphQL types include Int
, Float
,
String
, Boolean
, and ID
. Let's use the previous example
again:
type Person { id: ID! name: String age: Int occupation: Occupation } type Occupation { title: String }
Singling out the name
and title
fields, both hold a String
scalar. Name
could return a string value like "John Smith
" and the title
could return something like "firefighter
". Some GraphQL implementations also support
custom scalars using the Scalar
keyword and implementing the type's behavior. However,
AWS AppSync currently doesn't support custom scalars. For a list of
scalars, see Scalar types in
AWS AppSync.
Inputs
Due to the concept of input and output types, there are certain restrictions in place when passing in arguments. Types that commonly need to be passed in, especially objects, are restricted. You can use the input type to bypass this rule. Inputs are types that contain scalars, enums, and other input types.
Inputs are defined using the input
keyword:
type Person { id: ID! name: String age: Int occupation: Occupation } type Occupation { title: String } input personInput { id: ID! name: String age: Int occupation: occupationInput } input occupationInput { title: String }
As you can see, we can have separate inputs that mimic the original type. These inputs will often be used in your field operations like this:
type Person { id: ID! name: String age: Int occupation: Occupation } type Occupation { title: String } input occupationInput { title: String } type Mutation { addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person }
Note how we're still passing occupationInput
in place of Occupation
to
create a Person
.
This is but one scenario for inputs. They don't necessarily need to copy objects 1:1, and in production code, you most likely won't be using it like this. It's good practice to take advantage of GraphQL schemas by defining only what you need to input as arguments.
Also, the same inputs can be used in multiple operations, but we don't recommend doing this. Each operation should ideally contain its own unique copy of the inputs in case the schema's requirements change.
Special objects
GraphQL reserves a few keywords for special objects that define some of the business logic for how your schema will retrieve/manipulate data. At most, there can be one of each of these keywords in a schema. They act as entry points for all requested data that your clients run against your GraphQL service.
Special objects are also defined using the type
keyword. Though they're used
differently from regular object types, their implementation is very similar.
One thing that wasn't mentioned in our schema example was the fact that your special object types
must also be defined in a schema
root. So when you export a schema in AWS AppSync, it might
look like this:
Enumerations
Enumerations, or enums, are special scalars that limit the legal arguments a type or field may have. This means that whenever an enum is defined in the schema, its associated type or field will be limited to the values in the enum. Enums are serialized as string scalars. Note that different programming languages may handle GraphQL enums differently. For example, JavaScript has no native enum support, so the enum values may be mapped to int values instead.
Enums are defined using the enum
keyword. Here's an example:
enum trafficSignals { solidRed solidYellow solidGreen greenArrowLeft ... }
When calling the trafficLights
enum, the argument(s) can only be
solidRed
, solidYellow
, solidGreen
, etc. It's common to use
enums to depict things that have a distinct but limited number of choices.
Unions/Interfaces
See Interfaces and unions in GraphQL.