More GraphQL Schemas and Types
Tags: webdev, node, graphql, javascript
Published: 2021-01-25 01:39:10

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**


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.