
# Schema & Type System

Unlike traditional REST APIs, GraphQL comes with a strong type system to describe your API. A GraphQL schema describes the data you can query using the API endpoint by defining a set of types and fields that are mapped to those types.

Read along to learn about various GraphQL types.

## Object Types

Object types in GraphQL describe an object with underlying fields that can be queried from your API endpoint.

As an example, an object type can be defined as shown below:

```graphql
type actors {
  name: String!
  appearsIn: [movie!]!
}
```

Here,`actors` is an object type and `name` and `appearsIn` are fields mapped to type `actors`.

## Scalar Types

> From The GraphQL Documentation:

In the example for object types above, field `name` is of type `String`. String in GraphQL is by default a scalar type. This means that it resolves to a definite value and cannot have further sub-fields while querying. Scalar types represent the leaves of a query.

GraphQL comes with a set of default scalar types out-of-the-box such as below:

- `Int`: A signed 32‐bit integer.
- `Float`: A signed double-precision floating-point value.
- `String`: A UTF‐8 character sequence.
- `Boolean`: true or false.
- `ID`: The ID scalar type represents a unique identifier, often used to re-fetch an object or as the key for a cache. The ID type is serialized in the same way as a String; however, defining it as an ID signifies that it is not intended to be human‐readable.

Fields can also be of types that are not scalar by default, but resolve to scalar values upon querying. For instance, in the following query, the `name` and `appearsIn` fields resolve to scalar types.

```graphql
{
  hero {
    name
    appearsIn
  }
}
```

This is because in the schema, `name` and `appearIn` do not have further queryable sub-fields as described below:

```graphql
{
 "data": {
   "hero": {
     "name": "R2-D2",
     "appearsIn": [
       "NEWHOPE",
       "EMPIRE",
       "JEDI"
     ]
   }
 }
}
```

## Lists and Non-nulls

> From the GraphQL documentation:

Object types, scalars, and enums are the only kinds of types you can define in GraphQL. But when you use the types in other parts of the schema, or in your query variable declarations, you can apply additional type modifiers that affect validation of those values.

Let's look at an example:

```graphql
type Character {
  name: String!
  appearsIn: [Episode]!
}
```

Here, we're using a String type and marking it as Non-Null by adding an exclamation mark `!` after the type name. This means that our server always expects to return a non-null value for this field, and if it ends up getting a null value that will actually trigger a GraphQL execution error, letting the client know that something has gone wrong.

The Non-Null type modifier can also be used when defining arguments for a field, causing the GraphQL server to return a validation error if a null value is passed either in the GraphQL string or the variables.

```graphql
query DroidById($id: ID!) {
 droid(id: $id) {
   name
 }
}
{
 "id": null
}
```

```graphql
{
 "errors": [
   {
     "message": "Variable \"$id\" of non-null type \"ID!\" must not be null.",
     "locations": [
       {
         "line": 1,
         "column": 17
       }
     ]
   }
 ]
}
```

```graphql
myField: [String!]
```

This means that the list itself can be null, but it can't have any null members. For example, in JSON:

```json
myField: null // valid
myField: [] // valid
myField: ['a', 'b'] // valid
myField: ['a', null, 'b'] // error

```

## Union types

When a query returns a union type, you can use `... on` to specify the query fields for a certain return type. These are also called inline fragments. For example, the `hero` query below returns a union type of either `Droid` or `Human`.

```graphql
query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    name
    ... on Droid {
      primaryFunction
    }
    ... on Human {
      height
    }
  }
}
```

## Connections

Connections are a type of response used whenever you are expecting multiple results that may require pagination. Each query return type that ends in "Connection" will include the following return fields:

```graphql
pageInfo: PageInfo!
edges: [SomethingEdge!]!
nodes: [Something!]!
```

### `PageInfo`

`pageInfo` returns an object that includes information about the returned page of results:

`hasPreviousPage: Boolean!`
Whether or not the result has a previous page.

`hasNextPage: Boolean!`
Whether or not the result has another page after it.

`startCursor: String`
The starting cursor that identifies the first page.

`endCursor: String`
The end cursor that identifies the last page.

### Edges

`edges` returns an array of edge objects, which includes the cursor and first node for that page. You can use this data to help with pagination.

### Nodes

`nodes` returns an array of whichever type you are expecting paginated results for.

### Arguments

Each of these queries also accepts the following arguments:
`first: Int`
`after: String`
`last: Int`
`before: String`

`first` and `last` both accept an integer, which sets the number of results returned for each page. `first` will paginate the results starting at the beginning, while `last` will start from the end. It is required to pass an argument for either `first` or `last`. If no argument is given, the query will not return any results.

`after` and `before` both accept a cursor, which you can use to request different pages. These are both optional arguments.

You can learn more about the connection model and pagination in the official GraphQL docs here: https://graphql.org/learn/pagination/
