GraphQL is a query language for our API and a server-side runtime for running queries by using a type system for our data.
In this article, we’ll look at some GraphQL data types including lists, required fields, interfaces, union types, and input types.
Lists and Non-Null
A non-null type can be created by using the !
type modifier.
With that added, it’ll make sure that we have to include the field when we’re making a query to the server.
The non-null modifier can be used for defining arguments for a field, which causes the GraphQL server to return a validation error if a null value is passed as that argument.
Lists work in a similar way. We can use square brackets to mark something as a list.
For example, we can use them together as follows:
type Person {
name: String!
addresses: [Address]!
}
In the code above, we marked the name
field as required and have the String
type. Also, we have an addresses
field which is a list of Address
objects, and it’s also marked as required.
If we have something like:
myField: [String!]
This means that the list itself can be null, but myField
can’t have any null members.
On the other hand, if we have:
myField: [String]!
then the list itself can’t be null, but it can contain null values.
We can nest any number of non-null and list modifiers according to our needs.
Interfaces
An interface is an abstract type that includes a certain set of fields that a type must include to implement the interface.
For example, we can create an interface as follows:
interface Person {
id: ID!
name: String!
friends: [Person]
}
This means that a type that implements Person
must have the exact fields as we listed above.
For example, we can create a type that implements the interface as follows:
type Employee implements Person{
id: ID!
name: String!
friends: [Person],
employeeId: String!
}
In the code above, we have the Employee
type that has all the fields above. We also have the employeeId
string.
Therefore, we can use interfaces to ensure that a type has at least the fields and types that are listed in the interface.
To query something with various types that are implemented by an interface, we can use inline fragments as follows:
query Employee($id: ID!) {
employee(id: $id) {
name
... on Employee {
employeeId
}
}
}
Union types
Unio types are similar to interfaces, but they don’t get to specify any common fields between types.
We can define a union type with the union
keyword as follows:
union Worker = Person | Employee
We’ll need to use a conditional fragment to be able to query any fields:
{
search(text: "an") {
__typename
... on Person {
name
}
... on Employee{
name
employeeId
}
}
}
The __typename
field is a String
that indicates the type of the response object.
Input types
We can create input types to pass in whole objects into a request. For example, we can define an input type as follows:
input PersonInput {
firstName: String!
lastName: String!
}
Then we can pass it into a mutation as follows:
mutation CreatePerson($person: PersonInput!) {
createReview(person: $person) {
firstName
lastName
}
}
The fields on an input object can refer to input object types, but we can’t mix input and output types in our schema. Input object types also can’t have arguments in their fields.
Conclusion
To make sure a field isn’t null we can use the exclamation mark to mark it non-null.
We can also use square brackets to mark that something is a list.
To define a list of set fields for types, we can use interfaces to make sure all types that implement an interface have the fields listed.
Union types are useful for letting us combine common fields of types that implement the same interface and avoid repeating fields in queries.
We can use input types to pass in whole objects into a mutation.