10 Jan 2019 Efficient AppSync backend API development for mobile/Web app with AWS Amplify
Why GraphQL and App Sync
GraphQL has taken the API world by storm as an alternative to REST APIs. One of its main benefits is to enable clients to query for just the data they need.
All the types that are exposed in an API are written down in a schema using the GraphQL Schema Definition Language (SDL). The schema works well with the Javascript type system. This schema serves as the contract between the client and the server to define how data can be accessed by the client. Once the schema is defined, the teams working on frontend and backend can do their work independently since they both are aware of the definite structure of the data that’s sent over the network. Frontend teams can easily test their applications by mocking the required data structures. Once the server is ready, the switch can be flipped for the client apps to load the data from the actual API.
AWS offers its own GraphQL serverless solution: AppSync. AWS AppSync enables developers to interact with their data by using a managed GraphQL service. AppSync integrates seamlessly with modern tools and frameworks, including React, React Native, iOS, and Android.
AWS Amplify is a rapid development tool to generate a AppSync backend infrastructure with CloudFormation template.
Demo Application
We will explore through a sample e-commerce application the process of developing a DynamoDB backed backend App Sync API. A subset of the data model will be used for demo purpose (see figure 1).

GraphQL schema definition
The first step is to create the GraphQL schema definition for your backend data structure. AWS Amplify CLI can generate a DynamoDB-backed backend infrastructure from a GraphQL schema. For that purpose, some directives are added to make to guide the mapping of the model to DynamoDB. Like @model to specify the storing types (tables) and @connection to specify relationships between @model object types. Below is the schema definition for our e-commerce application.
type Order @model {
id: ID!
status: OrderStatus!
dateOrderPlaced: AWSDateTime!
orderDetails: String
items: [OrderItem] @connection(name: "OrderOrderItems")
}
type OrderItem @model {
id: ID!
quantity: Int!
price: Float!
otherItemDetails: String
order: Order @connection(name: "OrderOrderItems")
product: Product @connection(name: "OrderItemProduct")
}
type Product @model {
id: ID!
name: String
price: Float!
size: String
description: String
orderItems: [OrderItem] @connection(name: "OrderProduct")
}
enum OrderStatus {
CANCELED
COMPLETED
ONHOLD
PROCESSING
PENDING_PAYMENT
}
DynamoDB-backed App Sync backend generation with AWS Amplify
AWS Amplify first has to installed, configured and initialised.
$ npm install --save aws-amplify
$ amplify configure
$ amplify init
The “amplify init” should be issued in the root folder of the application and creates the basic infrastructure to manage the backend resources which can go beyond the API (see figure 2).

The AppSync API infrastructure can then be created with the schema definition (see example of running the commands in figures 3 and 4-1). The add command create the CloudFormation template for the API and the push command provision the resources in the cloud. Thus the AppSync API is ready to be used (see figure 4-2).
$ amplify add api
$ amplify push



During the push command Amplify CLI can generate queries (read-only fetch) and mutations (write followed by a fetch), and subscriptions (long-lived requests that receive data in response to events) in the front-end. Amplify supports React/React Native, Angular and Vue frontends.
Components of the generated AppSync API
Data Source
An AppSync data source is a persistent storage system (DynamoDB or RDS) or a trigger (AWS Lambda), along with credentials for accessing that system or trigger. In the example, the data sources are the DynamoDB tables generated by AWS Amplify CLI (see figure 5).

Resolver
A resolver performs an operation (query or mutation) against a predefined data source. It is comprised of a request and a response mapping template, a data source name, and a version. The templates are written in Apache Velocity Template Language (VTL). Amplify generates resolvers for each CRUD operation across each model. Below is an example of resolver (see figures 6-1, 6-2 and 6-3).



Updated schema
The generated GraphQL schema does not include the directives and the queries and mutations have been added. The JSON version of the schema is added in the frontend as part of the integration with the backend. Below is an excerpt of the generated schema and a call to the mutation createProduct in the query interface offered by AWS AppSync (see figure 7).
schema {
query: Query
mutation: Mutation
}
…
type Mutation {
createOrder(input: CreateOrderInput!): Order
createOrderItem(input: CreateOrderItemInput!): OrderItem
createProduct(input: CreateProductInput!): Product
deleteOrder(input: DeleteOrderInput!): Order
deleteOrderItem(input: DeleteOrderItemInput!): OrderItem
deleteProduct(input: DeleteProductInput!): Product
updateOrder(input: UpdateOrderInput!): Order
updateOrderItem(input: UpdateOrderItemInput!): OrderItem
updateProduct(input: UpdateProductInput!): Product
}
…
input CreateProductInput {
description: String
name: String
price: Float!
size: String
}

AppSync API call from the frontend with React
AWS Amplify facilitates the integration of the backend with JavaScript frameworks like React, Angular and Vue. It generates a configuration file, aws-exports.js, in your project root src folder. Import the file to configure your app to work with your AWS AppSync GraphQL backend.
import Amplify from 'aws-amplify';
import config from './aws-exports';
Amplify.configure(config);
The Amplify CLI generates all GraphQL statements (queries, mutations and subscriptions) and for JavaScript applications saves it in src/graphql folder. In order to call the mutation createProduct, import the generated mutation and execute it with API.graphQL :
import { API, graphqlOperation } from 'aws-amplify';
import {createProduct} from './graphql/mutations';
....
state = {
name: 'Chips',
price: 10.0,
description: 'Original salty chips',
created: false
}
async createProduct() {
try {
const response = await API.graphql(graphqlOperation(createProduct, {
input: {
name: this.state.name,
price: this.state.price,
description: this.state.description
}
}));
this.setState({created: true});
console.log(response);
} catch (error) {
console.log(error);
}
}
The result of a successful call is an JavaScript object with the data field as seen in figure 8.

Conclusion
Creating a DynamoDB-backed GraphQL AppSync API with Amplify is fairly easy as demonstrated in this article. AWS Amplify CLI facilitates the integration with a Javascript frontend. In a followup article, I will explore how to create a RDS GraphQL AppSync API using an AWS Lambda data source.
References
AWS re:Invent 2018: Ten tips And Tricks for Improving Your GraphQL API with AppSync (MOB401)
Defodji Sogbohossou
Posted at 06:20h, 26 March@Nicolas Silva
To be able to sort the results of a query by some field, a new parameter sortField has been added to the @connection directive (see https://aws-amplify.github.io/docs/cli/graphql).
directive @connection(name: String, keyField: String, sortField: String) on FIELD_DEFINITION
Below is an example:
type Order @model {
id: ID!
status: OrderStatus!
dateOrderPlaced: AWSDateTime!
orderDetails: String
items: [OrderItem] @connection(name: “OrderOrderItems”, sortField: “price”)
}