How to create a highly scalable serverless GraphQL data-driven app in minutes

Introduction to AWS AppSync

AWS AppSync allows you to create highly scalable serverless GraphQL data-driven mobile and web apps by providing an open source Amplify Framework (consisting of AWS AppSync Clients, GraphQL transforms and the CLI), integrations with multiple data sources, and the AWS AppSync console.

  • AWS AppSync Clients: client-side libraries to securely access data from any spec-compliant GraphQL API. Built-in support for real-time and offline/delta client synchronisation.
  • Amplify CLI: set of commands, via theapi category, to automate the setup and provision of resources for AWS AppSync and Amazon API Gateway cloud services. Support for REST and GraphQL APIs.
  • GraphQL Transforms: custom GraphQL schema directives that can be used in your GraphQL schema to enable custom workflows.
  • Data sources: databases (Amazon DynamoDB for NoSQL, Amazon Aurora for RDBMS), searches (Amazon Elasticsearch Service), and AWS Lambda functions.
AWS AppSync data-driven apps architecture overview

Setting up a new project with the Angular CLI

Before moving to the next section, please complete the steps described in “Setting up a new project with the Angular CLI”.

Creating a new GraphQL API

For this post we are going to create a GraphQL API to list our favourite restaurants. To create it, we will use the following command:

amplify add api
  • Please select from one of the below mentioned services GraphQL
  • Provide API name: RestaurantAPI
  • Choose an authorization type for the API API key
  • Do you have an annotated GraphQL schema? No
  • Do you want a guided schema creation? Yes
  • What best describes your project: Single object with fields (e.g., “Todo” with ID, name, description)
  • Do you want to edit the schema now? Yes
type Restaurant @model {
id: ID!
clientId: String
name: String!
description: String!
city: String!
}

Using your first GraphQL transform

GraphQL transforms allow AppSync to provide further customisation and support for common scenarios, so you don’t have to.

  • @key to configure custom index structures in DynamoDB
  • @searchable to enable searches using Amazon Elasticsearch Service
  • @connection to add relationships between types
  • @lambda to generate AWS Lambda resolvers
  • @auth to add fine grained multi-authorisation support
  • @versioned to add conflict resolution for offline scenarios

Pushing your GraphQL API to the cloud

Let’s run the push command to create the GraphQL API and see the results of using the @model transform:

amplify push
  • Are you sure you want to continue? Yes
  • Do you want to generate code for your newly created GraphQL API Yes
  • Choose the code generation language target typescript
  • Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.ts
  • Do you want to generate/update all possible GraphQL operations — queries, mutations and subscriptions Yes
  • Enter maximum statement depth [increase from default if your schema is deeply nested] 2
  • Enter the file name for the generated code src/API.ts
amplify console api
  • Please select from one of the below mentioned services GraphQL

Testing your new GraphQL API

Once in the AWS AppSync console, click on Queries on the left side. This will open an editor that we can use to edit and test GraphQL queries.

mutation createRestaurant {
createRestaurant(input: {
name: "Nobu"
description: "Great Sushi"
city: "New York"
}) {
id name description city
}
}
query listRestaurants {
listRestaurants {
items {
id
name
description
city
}
}
}
query searchRestaurants {
listRestaurants(filter: {
city: {
contains: "New York"
}
}) {
items {
id
name
description
city
}
}
}

Building the AppSync client

We are going to use the Amplify GraphQL client for Angular. Nonetheless, there are two AppSync clients available:

  • AWS AppSync SDK, integrated with the Apollo client, supports multiple authorization models, real-time, offline and caching.
  • Amplify GraphQL client, lighter option if you don’t require offline or caching capabilities.

Querying data with queries

In the earlier sections, we made sure we had a working GraphQL API. On the client, we will start by displaying a list.

import { API, graphqlOperation } from 'aws-amplify';
import { listRestaurants } from '../graphql/queries';
import { Restaurant } from './types/restaurant';
@Component({
template: `
<div>
<div *ngFor="let restaurant of restaurants">
{{ restaurant.name }}
</div>
</div>`
})
export class AppComponent implements OnInit {
restaurants: Array<Restaurant>;
async ngOnInit() {
var response = await API.graphql(graphqlOperation(listRestaurants))
this.restaurants = (response as any).data.listRestaurants.items;
}
}
listRestaurants(filter: ModelRestaurantFilterInput, limit: Int, nextToken: String): ModelRestaurantConnectiontype ModelRestaurantConnection {
items: [Restaurant]
nextToken: String
}

Creating data with mutations

In order to add new restaurants, we are going to create a form using FormBuilder to take the required user input and pass it forward to the createRestaurant mutation.

import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { createRestaurant } from '../../graphql/mutations'
@Component(...)
export class HomeComponent implements OnInit {
public createForm: FormGroup;
constructor(private fb: FormBuilder) { }async ngOnInit() {
this.createForm = this.fb.group({
'name': ['', Validators.required],
'description': ['', Validators.required],
'city': ['', Validators.required]
});
var response = await API.graphql(graphqlOperation(listRestaurants));
this.restaurants = (response as any).data.listRestaurants.items;
}

public async onCreate(restaurant: any) {
try {
await API.graphql(graphqlOperation(createRestaurant, {
input: restaurant
}));

console.log('item created!');
this.restaurants = [restaurant, ...this.restaurants];
this.createForm.reset();
}
catch (e) {
console.log('error creating restaurant...', e);
}
}
}
type Mutation {
createRestaurant(input: CreateRestaurantInput!): Restaurant
}
input CreateRestaurantInput {
id: ID
clientId: String
name: String!
description: String!
city: String!
}

Adding real-time with subscriptions

To demonstrate real-time, we are going to use a subscription to update AppSync clients when new restaurants are added. AppSync clients will subscribe to listen for changes going through our GraphQL API. More specifically, restaurant creation mutations.

import * as Observable from 'zen-observable';
import { onCreateRestaurant } from '../../graphql/subscriptions';
@Component(...)
export class HomeComponent implements OnInit {
ngOnInit() {
var subscription = API.graphql(
graphqlOperation(onCreateRestaurant)
) as Observable<object>;


subscription.subscribe({
next: (sourceData) => {
const newRestaurant = (sourceData as any).value.data.onCreateRestaurant
this.restaurants = [newRestaurant, ...this.restaurants];
}
});
}
}

Publishing your app via the AWS Amplify Console

The first thing you need to do is create a new repo for this project. Once you’ve created the repo, copy the URL for the project to the clipboard and initialise git in your local project:

git initgit remote add origin repo@repoofyourchoice.com:username/project-name.gitgit add .git commit -m 'initial commit'git push origin master
AWS Amplify Console deployment steps.

Cleaning up cloud services

If at any time, you would like to delete a service from your project and your AWS Account, you can do this by running:

amplify remove authamplify push

Conclusion

Congratulations! You successfully built your first GraphQL API using Angular and AWS AppSync. Thanks for following this tutorial.

Thanks for reading!

Have you got any questions about this tutorial or AWS AppSync? Feel free to reach me anytime at @gerardsans.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Gerard Sans

Gerard Sans

6K Followers

Helping Devs to succeed #AI #web3 / ex @AWSCloud / Just be AWSome / MC Speaker Trainer Community Leader @web3_london / @ReactEurope @ReactiveConf @ngcruise