

# GraphQL type reference
<a name="type-reference"></a>

Scalar types in GraphQL represent primitive leaf values in a GraphQL schema. These are the most basic data types that resolve to a single value. Unlike object types, scalar types cannot have sub-fields. GraphQL comes with a set of default scalar types: 
+ **Int**: A signed 32-bit integer 
+ **Float**: A signed double-precision floating-point value 
+ **String**: A UTF-8 character sequence 
+ **Boolean**: A true or false value
+ **ID**: A unique identifier, often used to refetch an object or as the key for a cache

These scalar types serve as the building blocks for more complex types in your schema. They are used to define fields that contain simple, singular values. In addition to these built-in scalars, AWS AppSync provides you with additional scalars for different use cases. 

Interfaces and Unions in GraphQL are abstract types that allow for flexible and extensible schema design. They provide mechanisms for grouping related types and enabling polymorphic queries. An Interface in GraphQL is an abstract type that defines a set of fields that a type must include to implement the interface. It serves as a contract for objects by specifying a common set of fields that implementing types must have. Interfaces are useful when you want to return an object or field that can be of several different types, but still have some guaranteed fields. By contrast, a Union in GraphQL represents a type that could be one of several object types, but does not define any common fields between those types. Unions are helpful when you need to return a field that can be of multiple types, and these types don't necessarily share common fields. Both Interfaces and Unions are particularly useful in scenarios where a field might return different types of data, enabling clients to query for specific fields based on the returned type. 

This section is used as a reference for schema types.

**Topics**
+ [Scalar types in GraphQL](https://docs.aws.amazon.com/appsync/latest/devguide/scalars.html)
+ [Interfaces and unions in GraphQL](https://docs.aws.amazon.com/appsync/latest/devguide/interfaces-and-unions.html)

# Scalar types in GraphQL
<a name="scalars"></a>

A GraphQL object type has a name and fields, and those fields can have sub-fields. Ultimately, an object type's fields must resolve to *scalar* types, which represent the leaves of the query. For more information about object types and scalars, see [Schemas and types](https://graphql.org/learn/schema/) on the GraphQL website.

In addition to the default set of GraphQL scalars, AWS AppSync also lets you use the **service-defined** scalars that start with the *AWS* prefix. AWS AppSync doesn't support the creation of **user-defined** (custom) scalars. You must use either the default or *AWS* scalars. 

You cannot use *AWS* as a prefix for custom object types.

The following section is a reference for schema typing.

## Default scalars
<a name="graph-ql-base-scalars"></a>

GraphQL defines the following default scalars:

### Default scalars list
<a name="graph-ql-base-scalars-list"></a>

`ID`  
A unique identifier for an object. This scalar is serialized like a `String` but isn't meant to be human-readable.

`String`  
A UTF-8 character sequence.

`Int`  
An integer value between -(231) and 231-1.

`Float`  
An IEEE 754 floating point value.

`Boolean`  
A Boolean value, either `true` or `false`.

## AWS AppSync scalars
<a name="graph-ql-aws-appsync-scalars"></a>

AWS AppSync defines the following scalars:

### AWS AppSync scalars list
<a name="graph-ql-aws-appsync-scalars-list"></a>

`AWSDate`  
An extended [ISO 8601 date](https://en.wikipedia.org/wiki/ISO_8601#Calendar_dates) string in the format `YYYY-MM-DD`.

`AWSTime`  
An extended [ISO 8601 time](https://en.wikipedia.org/wiki/ISO_8601#Times) string in the format `hh:mm:ss.sss`.

`AWSDateTime`  
An extended [ISO 8601 date and time](https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations) string in the format `YYYY-MM-DDThh:mm:ss.sssZ`.

**Note**  
The `AWSDate`, `AWSTime`, and `AWSDateTime` scalars can optionally include a [time zone offset](https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators). For example, the values `1970-01-01Z`, `1970-01-01-07:00`, and `1970-01-01+05:30` are all valid for `AWSDate`. The time zone offset must be either `Z` (UTC) or an offset in hours and minutes (and, optionally, seconds). For example, `±hh:mm:ss`. The seconds field in the time zone offset is considered valid even though it's not part of the ISO 8601 standard.

`AWSTimestamp`  
An integer value representing the number of seconds before or after `1970-01-01-T00:00Z`.

`AWSEmail`  
An email address in the format `local-part@domain-part` as defined by [RFC 822](https://tools.ietf.org/html/rfc822).

`AWSJSON`  
A JSON string. Any valid JSON construct is automatically parsed and loaded in the resolver code as maps, lists, or scalar values rather than as the literal input strings. Unquoted strings or otherwise invalid JSON result in a GraphQL validation error.

`AWSPhone`  
A phone number. This value is stored as a string. Phone numbers can contain either spaces or hyphens to separate digit groups. Phone numbers without a country code are assumed to be US/North American numbers adhering to the [North American Numbering Plan (NANP)](https://en.wikipedia.org/wiki/North_American_Numbering_Plan).

`AWSURL`  
A URL as defined by [RFC 1738](https://tools.ietf.org/html/rfc1738). For example, `https://www.amazon.com/dp/B000NZW3KC/` or `mailto:example@example.com`. URLs must contain a schema (`http`, `mailto`) and can't contain two forward slashes (`//`) in the path part.

`AWSIPAddress`  
A valid IPv4 or IPv6 address. IPv4 addresses are expected in quad-dotted notation (`123.12.34.56`). IPv6 addresses are expected in non-bracketed, colon-separated format (`1a2b:3c4b::1234:4567`). You can include an optional CIDR suffix (`123.45.67.89/16`) to indicate subnet mask.

## Schema usage example
<a name="example-schema-usage"></a>

The following example GraphQL schema uses all of the custom scalars as an "object" and shows the resolver request and response templates for basic put, get, and list operations. Finally, the example shows how you can use this when running queries and mutations.

```
type Mutation {
    putObject(
        email: AWSEmail,
        json: AWSJSON,
        date: AWSDate,
        time: AWSTime,
        datetime: AWSDateTime,
        timestamp: AWSTimestamp,
        url: AWSURL,
        phoneno: AWSPhone,
        ip: AWSIPAddress
    ): Object
}

type Object {
    id: ID!
    email: AWSEmail
    json: AWSJSON
    date: AWSDate
    time: AWSTime
    datetime: AWSDateTime
    timestamp: AWSTimestamp
    url: AWSURL
    phoneno: AWSPhone
    ip: AWSIPAddress
}

type Query {
    getObject(id: ID!): Object
    listObjects: [Object]
}

schema {
    query: Query
    mutation: Mutation
}
```

Here's what a request template for `putObject` might look like. A `putObject` uses a `PutItem` operation to create or update an item in your Amazon DynamoDB table. Note that this code snippet doesn't have a configured Amazon DynamoDB table as a data source. This is being used as an example only:

```
{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        "id": $util.dynamodb.toDynamoDBJson($util.autoId()),
    },
    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
```

The response template for `putObject` returns the results:

```
$util.toJson($ctx.result)
```

Here's what a request template for `getObject` might look like. A `getObject` uses a `GetItem` operation to return a set of attributes for the item given the primary key. Note that this code snippet doesn't have a configured Amazon DynamoDB table as a data source. This is being used as an example only:

```
{
    "version": "2017-02-28",
    "operation": "GetItem",
    "key": {
        "id": $util.dynamodb.toDynamoDBJson($ctx.args.id),
    }
}
```

The response template for `getObject` returns the results:

```
$util.toJson($ctx.result)
```

Here's what a request template for `listObjects` might look like. A `listObjects` uses a `Scan` operation to return one or more items and attributes. Note that this code snippet doesn't have a configured Amazon DynamoDB table as a data source. This is being used as an example only:

```
{
    "version" : "2017-02-28",
    "operation" : "Scan",
}
```

The response template for `listObjects` returns the results:

```
$util.toJson($ctx.result.items)
```

The following are some examples of using this schema with GraphQL queries:

```
mutation CreateObject {
    putObject(email: "example@example.com"
        json: "{\"a\":1, \"b\":3, \"string\": 234}"
        date: "1970-01-01Z"
        time: "12:00:34."
        datetime: "1930-01-01T16:00:00-07:00"
        timestamp: -123123
        url:"https://amazon.com"
        phoneno: "+1 555 764 4377"
        ip: "127.0.0.1/8"
    ) {
        id
        email
        json
        date
        time
        datetime
        url
        timestamp
        phoneno
        ip
    }
}

query getObject {
    getObject(id:"0d97daf0-48e6-4ffc-8d48-0537e8a843d2"){
        email
        url
        timestamp
        phoneno
        ip
    }
}

query listObjects {
    listObjects {
        json
        date
        time
        datetime
    }
}
```

# Interfaces and unions in GraphQL
<a name="interfaces-and-unions"></a>

The GraphQL type system supports [Interfaces](https://graphql.org/learn/schema/#interfaces). An interface exposes a certain set of fields that a type must include to implement the interface. 

The GraphQL type system also supports [Unions](https://graphql.org/learn/schema/#union-types). Unions are identical to interfaces, except that they don’t define a common set of fields. Unions are generally preferred over interfaces when the possible types do not share a logical hierarchy.

The following section is a reference for schema typing.

## Interface examples
<a name="interfaces"></a>

We could represent an `Event` interface that represents any kind of activity or gathering of people. Some possible event types are `Concert`, `Conference`, and `Festival`. These types all share common characteristics, including a name, a venue where the event is taking place, and a start and end date. These types also have differences; a `Conference` offers a list of speakers and workshops, while a `Concert` features a performing band.

In Schema Definition Language (SDL), the `Event` interface is defined as follows:

```
interface Event {
        id: ID!
        name : String!
        startsAt: String
        endsAt: String
        venue: Venue
        minAgeRestriction: Int
}
```

And each of the types implements the `Event` interface as follows:

```
type Concert implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performingBand: String
}

type Festival implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performers: [String]
}

type Conference implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    speakers: [String]
    workshops: [String]
}
```

Interfaces are useful to represent elements that might be of several types. For example, we could search for all events happening at a specific venue. Let’s add a `findEventsByVenue` field to the schema as follows:

```
schema {
    query: Query
}

type Query {
    # Retrieve Events at a specific Venue
    findEventsAtVenue(venueId: ID!): [Event]
}

type Venue {
    id: ID!
    name: String
    address: String
    maxOccupancy: Int
}

type Concert implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performingBand: String
}

interface Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
}

type Festival implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performers: [String]
}

type Conference implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    speakers: [String]
    workshops: [String]
}
```

The `findEventsByVenue` returns a list of `Event`. Because GraphQL interface fields are common to all the implementing types, it’s possible to select any fields on the `Event` interface (`id`, `name`, `startsAt`, `endsAt`, `venue`, and `minAgeRestriction`). Additionally, you can access the fields on any implementing type using GraphQL [fragments](https://graphql.org/learn/queries/#fragments), as long as you specify the type.

Let’s examine an example of a GraphQL query that uses the interface.

```
query {
  findEventsAtVenue(venueId: "Madison Square Garden") {
    id
    name
    minAgeRestriction
    startsAt

    ... on Festival {
      performers
    }

    ... on Concert {
      performingBand
    }

    ... on Conference {
      speakers
      workshops
    }
  }
}
```

The previous query yields a single list of results, and the server could sort the events by start date by default.

```
{
  "data": {
    "findEventsAtVenue": [
      {
        "id": "Festival-2",
        "name": "Festival 2",
        "minAgeRestriction": 21,
        "startsAt": "2018-10-05T14:48:00.000Z",
        "performers": [
          "The Singers",
          "The Screamers"
        ]
      },
      {
        "id": "Concert-3",
        "name": "Concert 3",
        "minAgeRestriction": 18,
        "startsAt": "2018-10-07T14:48:00.000Z",
        "performingBand": "The Jumpers"
      },
      {
        "id": "Conference-4",
        "name": "Conference 4",
        "minAgeRestriction": null,
        "startsAt": "2018-10-09T14:48:00.000Z",
        "speakers": [
          "The Storytellers"
        ],
        "workshops": [
          "Writing",
          "Reading"
        ]
      }
    ]
  }
}
```

Since results are returned as a single collection of events, using interfaces to represent common characteristics is very helpful for sorting results.

## Union examples
<a name="unions"></a>

As stated earlier, unions don't define common sets of fields. A search result might represent many different types. Using the `Event` schema, you can define a `SearchResult` union as follows:

```
type Query {
    # Retrieve Events at a specific Venue
    findEventsAtVenue(venueId: ID!): [Event]
    # Search across all content
    search(query: String!): [SearchResult]
}

union SearchResult = Conference | Festival | Concert | Venue
```

In this case, to query any field on our `SearchResult` union, you must use fragments:

```
query {
  search(query: "Madison") {
    ... on Venue {
      id
      name
      address
    }

    ... on Festival {
      id
      name
      performers
    }

    ... on Concert {
      id
      name
      performingBand
    }

    ... on Conference {
      speakers
      workshops
    }
  }
}
```

## Type resolution in AWS AppSync
<a name="type-resolution-in-appsynclong"></a>

Type resolution is the mechanism by which the GraphQL engine identifies a resolved value as a specific object type.

Going back to the union search example, provided our query yielded results, each item in the results list must present itself as one of the possible types that the `SearchResult` union defined (that is, `Conference`, `Festival`, `Concert`, or `Venue`).

Because the logic to identify a `Festival` from a `Venue` or a `Conference` is dependent on the application requirements, the GraphQL engine must be given a hint to identify our possible types from the raw results.

With AWS AppSync, this hint is represented by a meta field named `__typename`, whose value corresponds to the identified object type name. `__typename` is required for return types that are interfaces or unions.

## Type resolution example
<a name="type-resolution-example"></a>

Let’s reuse the previous schema. You can follow along by navigating to the console and adding the following under the **Schema** page:

```
schema {
    query: Query
}

type Query {
    # Retrieve Events at a specific Venue
    findEventsAtVenue(venueId: ID!): [Event]
    # Search across all content
    search(query: String!): [SearchResult]
}

union SearchResult = Conference | Festival | Concert | Venue

type Venue {
    id: ID!
    name: String!
    address: String
    maxOccupancy: Int
}

interface Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
}

type Festival implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performers: [String]
}

type Conference implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    speakers: [String]
    workshops: [String]
}

type Concert implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performingBand: String
}
```

Let’s attach a resolver to the `Query.search` field. In the `Resolvers` section, choose **Attach**, create a new **Data Source** of type *NONE*, and then name it *StubDataSource*. For the sake of this example, we’ll pretend we fetched results from an external source, and hard code the fetched results in the request mapping template.

In the request mapping template pane, enter the following:

```
{
    "version" : "2018-05-29",
    "payload":
    ## We are effectively mocking our search results for this example
    [
        {
            "id": "Venue-1",
            "name": "Venue 1",
            "address": "2121 7th Ave, Seattle, WA 98121",
            "maxOccupancy": 1000
        },
        {
            "id": "Festival-2",
            "name": "Festival 2",
            "performers": ["The Singers", "The Screamers"]
        },
        {
            "id": "Concert-3",
            "name": "Concert 3",
            "performingBand": "The Jumpers"
        },
        {
            "id": "Conference-4",
            "name": "Conference 4",
            "speakers": ["The Storytellers"],
            "workshops": ["Writing", "Reading"]
        }
    ]
}
```

If the application returns the type name as part of the `id` field, the type resolution logic must parse the `id` field to extract the type name and then add the `__typename` field to each of the results. You can perform that logic in the response mapping template as follows:

**Note**  
You can also perform this task as part of your Lambda function, if you are using the Lambda data source.

```
#foreach ($result in $context.result)
    ## Extract type name from the id field.
    #set( $typeName = $result.id.split("-")[0] )
    #set( $ignore = $result.put("__typename", $typeName))
#end
$util.toJson($context.result)
```

Run the following query:

```
query {
  search(query: "Madison") {
    ... on Venue {
      id
      name
      address
    }

    ... on Festival {
        id
      name
      performers
    }

    ... on Concert {
      id
      name
      performingBand
    }

    ... on Conference {
      speakers
      workshops
    }
  }
}
```

The query yields the following results:

```
{
  "data": {
    "search": [
      {
        "id": "Venue-1",
        "name": "Venue 1",
        "address": "2121 7th Ave, Seattle, WA 98121"
      },
      {
        "id": "Festival-2",
        "name": "Festival 2",
        "performers": [
          "The Singers",
          "The Screamers"
        ]
      },
      {
        "id": "Concert-3",
        "name": "Concert 3",
        "performingBand": "The Jumpers"
      },
      {
        "speakers": [
          "The Storytellers"
        ],
        "workshops": [
          "Writing",
          "Reading"
        ]
      }
    ]
  }
}
```

The type resolution logic varies depending on the application. For example, you could have a different identifying logic that checks for the existence of certain fields or even a combination of fields. That is, you could detect the presence of the `performers` field to identify a `Festival` or the combination of the `speakers` and the `workshops` fields to identify a `Conference`. Ultimately, it is up to you to define the logic you want to use.