How: Auto-Populated Schema Fields in AWS Amplify
Tags: aws, serverless
Published: 2021-05-05 19:10:30

Unsplash photo by Luke Richardson

---

Not too long ago, I was building a schema using [AWS Amplify](https://docs.amplify.aws/). 

Simplified a bit, it looked like this:

```graphql
type Game @model {
  id: ID!
  gameName: String!
  player1: String!
  player2: String!
  currentPlayer: String!
  board: AWSJSON!
}
```

## Context

> 🗒️ For context on this scenario: Amplify is using [AppSync](https://aws.amazon.com/appsync/) under the hood -- A managed GraphQL API.

Furthermore, here's a breakdown of the field values:

| Value | Description |
|-|-|
| ID! | A string that is implied to be unique. Required. |
| String! | Any sequence of string characters. Required. |
| AWSJSON! | Any value that is able to be stringified as JSON. This will automatically do the stringifying. Required. |

The last piece to talk about is the `@model` _directive_. 

By just adding that directive to our schema, Amplify will create mappings for common CRUD operations. The mapping will be between AppSync and DynamoDB.

In short, we'll have a way to create, read, update, and delete a game from our frontend, and have that data available in a database.

## Learn and Be Curious

When I push this model up to AWS using the Amplify CLI:

```sh
amplify push
```

Amplify will generate files so that I can perform those CRUD operations from my frontend. So to create a game, I would call the necessary methods, passing in the query, and the required fields:

```js
const board = [[], [], []]
API.graphql(
  {
    query: createGame, 
    variables: 
    {
      input: {
        player1: "Michael",
        player2: "Jessica", 
        currentPlayer: "Michael", 
        board: board
      }
    }
)
```

> 🗒️ Note that we didn't provide an `id` -- a required field.

The method above will return a JavaScript Promise. Assuming the call to create a game is successful, we will be able to dive into the response and see the following object returned:

```js
{
  __typename: "Game",
  id: "s0m3-long-s3qnenc3",
  createdAt: 24324322 // an ISO Date
  updatedAt: 24324322,
  player1: "Michael",
  player2: "Jessica", 
  currentPlayer: "Michael",
  board: "[[], [], []]"
}
```

> Where did the extra fields come from?

Well, looking at the [AppSync documentation](https://docs.aws.amazon.com/appsync/latest/devguide/scalars.html) for scalar types, you'll find this snippet:

![$util.dynamodb.toDynamoDBJson($util.autoId()](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b5m81o0p41uhy0i3jsrx.png)

Recall that there is a mapping between AppSync and DynamoDB. The image above is a _request_ mapping. Written in VTL or [Velocity Template Language](https://velocity.apache.org/engine/devel/vtl-reference.html). 

In short, it's a way to specify data that goes from AppSync to DynamoDB. In this case, it's creating a unique value and adding it to the `id` field.

"So if Amplify is doing this part for us, then where can we find it?"

Great question, glad you asked!

![Request VTL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jxdribpf29f98wi310td.png)

Amplify provides all of the mapping templates in the `resolvers` directory. Taking a peek inside of the, we see the following:

![VTL syntax](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w8hpbvi7ykhau3h2z38o.png)

Here are the main points worth mentioning:

* Line 2: If an `id` value is null, create a value
* Line 3: Create a value for `createdAt`. Apply it to line 5
* Line 10: Create the `__typename` and set it to `Game`

## Conclusion

Understanding the moving parts can be tricky at first, however pulling back the curtains to reveal the magic is greatly beneficial.

Specifically, you've not only learned how certain fields are created automatically but also how you can tweak a VTL template so that your own fields are automatically added as well!