Provision from schema (optional) - AWS AppSync

Provision from schema (optional)

AWS AppSync can automatically provision Amazon DynamoDB tables from a schema definition, create data sources, and connect the resolvers on your behalf. This can be useful if you want to let AWS AppSync define the appropriate table layout and indexing strategy based on your schema definition and data access patterns.

You can also start with no schema and build it up from a type, letting AWS AppSync create the schema definition and different filtering options. You can use the two flows outlined in this topic independently or together throughout the lifecycle of your API.

No Schema

After you create an AWS AppSync API, go to the Schema page and choose Create Resources. The editor at the top contains a pre-defined template for a type. You can change the name, field types, and add or remove entries. For example, use the following sample type:

type Blog { id: ID! title: String! content: String rating: Int approved: Boolean }

Lower on the page, you can change the table name, change the layout, or add indexes. Indexes are recommended as a best practice for performance if you plan to query often using a specific field. When creating an index, AWS AppSync builds the GraphQL schema and connects resolvers for you. For example, choose Add Index and name the index rating. In Primary Key, choose rating. In Sort Key, leave the default none. You should see a query like the following in the GraphQL that’s generated:

queryBlogsByRating(rating:Int!, first:Int, nextToken: String): BlogConnection

After you’ve finished editing your type and creating any needed indices, choose Create, and then wait for the process to complete creating resources and connecting data sources to resolvers. You can go to the Queries page immediately and start running mutations, queries, and subscriptions. For example, create a blog post with the following mutation:

mutation add { createBlog(input:{ title:"My first post" content:"You can use AppSync with GraphQL" rating:5 approved:true }){ id } }

Notice that the id field is automatically generated. AWS AppSync does this if your type has a Primary Key field on a table of id: ID!. Otherwise, AWS AppSync require the Primary Key field to be passed as part of the argument. After creating a few blog posts with different content, run the following query:

query list { listBlogs(filter:{ content:{ contains:"AppSync" }}){ items{ id title content rating } } }

It should only return the blogs with the string “AppSync” in the content field. You can explore the different filters on fields via GraphQL introspection on the Queries page of the console. AWS AppSync generates several queries and filters for common use cases on different scalar types to help you get up and running fast. It’s important to note that as your application usage grows larger and you have more complex data requirements around scale or larger tables, all of these filters might no longer be appropriate and you should leverage different DynamoDB best practices or combine data sources in your GraphQL API, such as Amazon OpenSearch Service for complex searches.

AWS AppSync creates filters on GraphQL scalar types (that is, ID, String, Int, Float, Boolean) for list operations. This is done by creating a base input type that contains the different fields for your defined type. Each one of these fields has an input filter type as appropriate for things like string searches, Boolean comparisons, etc. For example, only String supports BEGINS_WITH while Boolean supports EQ, NE, etc. You can view the supported operations in the generated GraphQL input types on the Schema page and a list of DynamoDB operations at DynamoDB operations.

Continuing with the blog example type, the following generates a base input type in your schema:

input BlogInput { id: TableIDFilterInput title: TableStringFilterInput content: TableStringFilterInput rating: TableIntFilterInput approved: TableBooleanFilterInput }

The AWS AppSync console automatically connects this to a query operation. If you want to do this yourself, it might look like the following:

listBlog(filter: BlogInput): [Blog]

When you attach a resolver to the listBlog query, the request mapping template uses the input on the filter key along with $util.transform.toDynamoDBFilterExpression as follows:

{ "version": "2017-02-28", "operation": "Scan", "filter": #if($context.args.filter) $util.transform.toDynamoDBFilterExpression($ctx.args.filter) #else null #end }

Existing Schema

These instructions start with the schema outlined in Designing Your Schema. From the AWS AppSync console, go to the Schema page, enter the following schema into the editor, and then choose Save Schema:

schema { query:Query mutation: Mutation } type Query { allTodo: [Todo] } type Mutation { addTodo(id: ID!, name: String, description: String, priority: Int, status: TodoStatus): Todo } type Todo { id: ID! name: String description: String priority: Int status: TodoStatus } enum TodoStatus { done pending }

After you save a schema, choose Create resources at the top of the page. Choose Use existing type, and then choose your Todo type. In the form that appears, you can configure the table details. You can change your DynamoDB primary or sort keys here, and add additional indexes. At the bottom of the page is a corresponding section for the GraphQL queries and mutations that are available to you, based on different key selections. AWS AppSync will provision DynamoDB tables that best match your data access pattern for efficient use of your database throughput. You can also select indices for different query options, which set up a DynamoDB local secondary index or global secondary indexes, as appropriate.

For the example schema, you can simply have id selected as the primary key and choose Create. If your type doesn’t have id set as the primary key, all of the fields for that type are required for create operations. Otherwise, AWS AppSync automatically generates unique IDs for you in the resolvers. After a moment, your DynamoDB tables are created, data sources are created, and resolvers are connected. You can run mutations and queries as described in Using Your API.

Note: There’s a GraphQL input type for the arguments of the created schema. For example, if you provision from a schema with a GraphQL type Books {...}, there might be an input type like the following:

input CreateBooksInput { ISBN: String! Author: String Title: String Price: Int }

To use this in a GraphQL query or mutation, you would use the following:

mutation add { createBooks(input:{ ISBN:"2349238" Author:"Nadia Bailey" Title:"Running in the park" Price:10 }){ ISBN Author } }

Also, as explained earlier in No Schema section of this document, default filters will be created for list operations. For example, if you want to return all items where the price is greater than 5, you could run the following:

query list { listBooks(filter:{ Price:{ gt:5 }}){ items{ ISBN Author Title Price } } }