Serverless AppSync Plugin: Top 10 New Features

Benoît Bouré
HackerNoon.com
7 min readApr 23, 2019

--

If you are not familiar with AppSync or the plugin yet, we suggest you to read the following posts first:

Part 1: Introduction: GraphQL endpoints with API Gateway + AWS Lambda
Part 2: AppSync Backend: AWS Managed GraphQL Service
Part 3: AppSync Frontend: AWS Managed GraphQL Service
Part 4: Serverless AppSync Plugin: New Features (this blog)

Introduction

AWS AppSync is a fully managed serverless GraphQL service for real-time data queries, synchronization, communications, and offline programming features. It is great for building scalable data-driven mobile, web or enterprise applications quickly, and without the hassle of managing complex infrastructures.

Serverless AppSync plugin allows you to develop and test your AppSync GraphQL API locally on your workstation. You can use this plugin as a part of your continuous integration and continuous deployment (CI/CD) framework to deploy your GraphQL API automatically in production.

This plugin is built on the top of the serverless framework and has received a great reception from the open source GraphQL community since its launch last year in 2018. So far, we have released 17+ versions of the plugin which has 450+ stars on GitHub, 65K+ total npm downloads and 45+ contributors have helped to close 100+ open GitHub issues. There is even a youtube video showing it in action. The open source community has been doing a great job over the last few months to improve the features of this plugin, and we have received dozens of pull requests.

In this post, we will outline some of the important features added to this plugin over the past few months…

What is new?

1) AppSync Offline Support

Have you ever dreamt about speeding your AppSync development cycles by testing your AppSync resolvers locally?

Offline support has been a recurring topic of discussion among the AppSync users, and thanks to James and Andreas, your dream has come true! The AppSync Emulator, which is built on top of the AppSync plugin, gives you the flexibility to test and develop the AppSync API in your local environment. Now, you don’t have to deploy your code every time you make a change :)

This plugin extension will even spin up the emulator automatically for you.

Sample code (Reference)

plugins:
- serverless-appsync-plugin
- serverless-dynamodb-local
- serverless-appsync-offline
- serverless-offline

custom:
appsync-offline:
port: 62222
dynamodb:
client:
endpoint: "http://localhost:8000"
region: localhost

The serverless appsync-offline start command can be triggered automatically when using serverless-offline plugin.

2) Auto-generated roles and policies

Have you ever struggled to create the right IAM roles and policies for your data sources?

Creating, updating and managing IAM policies, statements and actions for the AppSync data sources is not an easy task. On top of that, it usually ends up adding extra boilerplate code to your serverless yaml file. The plugin now fixes this problem by generating IAM roles and policies for you, based on the type of the data source and its target.

For instance, a lambda data source will automatically be assigned a policy that allows it to execute the target lambda function, and a given set of DynamoDB data sources will be authorized to execute all read/write actions on the target table. In addition to that, customizing the policy is now much easier to do with the new iamRoleStatements config.

Sample code:

dataSources:
- type: AMAZON_DYNAMODB
name: DynamoDBDataSource
description:
config:
tableName: myTable
#allow datasource to execute GetItem on "myTable"
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:GetItem"
Resource:
- "arn:aws:dynamodb:{REGION}:{ACCOUNT_ID}:myTable"
- "arn:aws:dynamodb:{REGION}:{ACCOUNT_ID}:myTable/*"

You still can specify a serviceRoleArn if you want more fine-grained control over the role and policies. When specified, it will be used in priority over iamRoleStatements.

PR: https://github.com/sid88in/serverless-appsync-plugin/pull/141

3) RDS data sources

DynamoDB is great, but all I really need is a good old relational database. Is that supported yet?

AWS introduced Relational Databases support in November 2018. It allows accessing relational databases, like MySQL, running on Aurora directly from your data sources and mapping templates. Thanks to Alex, the answer to the question is YES!. You can now say goodbye to your AWS Lambda functions, and cut off some latency and bills!

Sample code:

- type: RELATIONAL_DATABASE
name: My relational DB resolver
config:
dbClusterIdentifier: { Ref: RDSCluster }
awsSecretStoreArn: { Ref: RDSClusterSecret }
databaseName: rds_db
schema: mysql

As described in the previous feature, this plugin will auto-generate the rds data source policies for you, unless you specify custom ones.

PR: https://github.com/sid88in/serverless-appsync-plugin/pull/226

4) Pipeline resolvers

Were you expecting the recently launched pipeline resolvers to be added to this plugin?

AWS introduced pipeline resolvers into AppSync with Relational Databases. They enable execution of one or more operations against multiple data sources in order, on a single GraphQL field. This allows orchestration of actions by composing code into a single resolver, or sharing code across resolvers.

Thanks for C K, this is now supported in this plugin.

Sample Code:

custom:
appsync:
mappingTemplates:
- type: Query
field: testPipelineQuery
request: 'start.vtl'
response: 'common-response.vtl'
kind: PIPELINE
functions:
- authorizeFunction
- fetchDataFunction
functionConfigurations:
- dataSource: graphqlLambda
name: 'authorizeFunction'
request: './mapping-templates/authorize-request.vtl'
response: './mapping-templates/common-response.vtl'
- dataSource: dataTable
name: 'fetchDataFunction'
request: './mapping-templates/fetchData.vtl'
response: './mapping-templates/common-response.vtl'

For more info about pipeline resolvers and how to use them, please refer to the AWS documentation.

PR: https://github.com/sid88in/serverless-appsync-plugin/pull/181

5) Multiple API support

Does your project require more than just one GraphQL API? This one's for you!

Imagine you have two APIs in your project: one for public access (unauthenticated), and another one using custom authentication for internal use. Thanks to Alex, the appsync config key now supports receiving an array of objects, each one representing the config of a single API which allows you to deploy multiple AppSync GraphQL endpoints in a single deployment.

Sample Code:

custom:
appsync:
- name: public-api
authenticationType: API_KEY
schema: public.graphql
# ...
- name: private-api
authenticationType: AMAZON_COGNITO_USER_POOLS
schema: private.graphql
# ...

Note that there is no restriction at all on sharing resources between both APIs, like mapping template or data source definitions; or even the schema definition, but keep in mind that the resulting AppSync APIs will be completely independent and deployed in a single CF stack. The underlying external resources like AWS Lambda functions, DynamoDB tables, etc. can be shared by both the APIs.

PR: https://github.com/sid88in/serverless-appsync-plugin/pull/155

6) GraphQL Schema stitching

So, your API is growing, and you have dozens of queries, mutations, and subscriptions which result in big monolith schema.graphql file.

Big files are not human-friendly, they are hard to read, and it can be a real nightmare to maintain. Thanks to Ilya and schema stitching, you can now split your schema into several files, and they will get merged for you before your AppSync API gets deployed.

Sample Code:

custom:
appSync:
schema:
- path/to/schema_base.graphql
- path/to/schema_internal.graphql

PR: https://github.com/sid88in/serverless-appsync-plugin/pull/227

7) External data source and mapping template reference

If you have a big graphql schema, the chances are that you have huge data source and mapping template config files as well…

Just like you can split your data schema, you can now also split your data source and mapping template definitions into separate files. Thanks to Hari you can now do this:

Before

appSync:
datasources:
- type: AMAZON_DYNAMODB
name: posts
description: "Posts table datasource"
config:
tableName: posts
- type: AWS_LAMBDA
name: users
description: "Users lambda datasource"
config:
functionName: getUsers
- # a long list of datasources
mappingTemplates:
- dataSource: posts
type: Query
field: getPost
request: "Query.getPost.request.vtl"
response: "Query.getPost.response.vtl"
- dataSource: users
type: Query
field: getUsers
request: "Query.getUsers.request.vtl"
response: "Query.getUsers.response.vtl"
- # a long list of mapping templates

After

Simply move your data source and mapping template definitions into separate files, and reference them as follow.

appSync:
datasources:
- ${file(datasources/dynamodb.yml)}
- ${file(datasources/lambda.yml)}
mappingTemplates:
- ${file(mapping-templates/posts.yml)}
- ${file(mapping-templates/users.yml)}

PRs: https://github.com/sid88in/serverless-appsync-plugin/pull/216 and https://github.com/sid88in/serverless-appsync-plugin/pull/182

8) Simplified data source function config

Remember when you had to manually reference your functions ARN in their data source? There is now an easier way.

It is not necessary anymore to reference AWS Lambda functions by their ARN in data sources config. Providing the function’s key from the functions serverless config is much easier. The plugin will automatically resolve the function’s ARNs for you.

Before

functions:
getUser:
...
custom:
appsync:
datasources:
- type: AWS_LAMBDA
name: myLambdaDatasource
config:
lambdaFunctionArn: {Fn::GetAtt: GetUserLambdaFunction, Arn]}

After

functions:
getUser:
...
custom:
appsync:
datasources:
- type: AWS_LAMBDA
name: myLambdaDatasource
config:
functionName: getUser

PR: https://github.com/sid88in/serverless-appsync-plugin/pull/215

9) Default filename conventions for mapping templates

Did you ever want to simplify even more your mapping templates? We are now a step further…

Thanks to Carl-Johan, you don’t need to explicitly specify your mapping template file names. Instead, you can follow the following naming conventions:

{Type}.{Field}.request.vtl # for mapping template requests
{Type}.{Field}.response.vtl # for mapping template responses

Before

mappingTemplates:
- field: getSomeData
dataSource: myDatasource
type: Query
request: getSomeData.request.vtl
response: getSomeData.response.vtl

After

mappingTemplates:
- field: getSomeData
dataSource: myDatasource
type: Query
#request: defaults to Query.getSomeData.request.vtl
#response: defaults to Query.getSomeData.response.vtl

The plugin will keep looking into the mapping-templates folder for the files, or from the path specified into the mappingTemplatesLocation config, but with the default name. Of course, it is still possible to specify a custom filename, just like before.

PR: https://github.com/sid88in/serverless-appsync-plugin/pull/206

10) Enhanced Stack Output

What is my endpoint URL? What is the API key? Ever asked yourself these questions after a deploy? Tired of going into the AppSync Console to figure it out? Keep reading!

After a successful deployment (or after calling sls info), the plugin will now output meaningful information about the deployed stack in the Service Information section. That includes generated API keys (if you are using the API_KEY authentication type) and the AppSync endpoints. Check this out:

Service Information
-------------------
service: blogs-api
stage: dev
region: us-east-1
stack: blogs-api-dev
resources: 42
api keys:
None
appsync api keys:
da2-xxxxxxxxxx
endpoints:
None
appsync endpoints:
https://xxxxxxx.appsync-api.us-east-1.amazonaws.com/graphql

PR: https://github.com/sid88in/serverless-appsync-plugin/pull/215

What’s next?

We are actively looking for contributors to this plugin. Please, feel free to get involved by opening issues with your thoughts, ideas, bug fixes or feature requests. Stay tuned for more ;)

Special Thanks

Thanks to Sid for creating this plugin and building an open source community around it; Hari, Carl-Johan, CK, Alex Ang, Alex Rozn, Andreas, Ilya and James for helping with the features exposed in this post and to all the other contributors that helped to make this plugin worth it. Last but not the least AWS AppSync team for their constant support and feedback to make this successful.

--

--