v2
of this plugin tries to keep backward compatibility with v1
from a CloudFormation perspective (i.e. Logical names are maintained). This pretends to make migration from v1
possible. However, the API has changed quite a bit.
This page will guide you through the process of migrating existing stacks to the newer version.
The v1 is still available on the v1 branch
There are a few breaking changes that you need to be aware of.
Due to a backwards-compatibility issue your API keys will get rotated
(changed) upon the first deployment with the v2
version of this plugin. If left unresolved, this will cause your clients that use the keys
to break, until you are able to update them with the newly generated API keys.
Make sure to read about mitigating the API key rotation issue
v2
only supports the new Serverless Framework v3. You will need to upgrade to SF v3 first.
Support for multiple APIs has been dropped in v2. There are several reasons for this:
- It was an edge case: Most users would only have one API per Stack
- It is probably bad practice: Different APIs should be considered different micro-services and be deployed separately.
- It is not supported by the Serverless Framework for API Gateway: SF does not support multiple API Gateways in a single Stack. Why should this plugin do for AppSync?
If you only have one API in your current stack, you should not worry about this change. You do need to make sure that you do not define your appSync
API as an array (even with one element only), though.
custom:
appSync:
name: my-api # ✅ Compatible with v2
appSync:
- name: my-api # ❌ Incompatible with v2
Workaround
Place your APIs into different stacks. Unfortunately, this WILL require the replacement of the APIs. You can probably use custom domains to workaround that, if that's an option.
The new default runtime is JavaScript.
The new default KIND
for resolvers is PIPELINE
. For several reasons:
- The JavaScript runtime, is only supported with PIPELINE resolvers
- It makes migrations easier later, if you need to add functions to your resolvers.
💡 To simulate a UNIT resolver, use a PIPELINE with only one function.
resolvers:
Query.getPost:
functions:
- dataSource: posts
code: resolvers/getPost.js
In v1
, if you did not specify a path to your mapping templates, a default based on the type, field or function name was used. (e.g. Query.getPost.request.vtl
).
To avoid unexpected behaviours, you are now required to explicitly specify the path to your resolver handlers. i.e. use code
for Pipeline JS resolvers or request
/response
for VTL.
There is also no more mappingTemplatesLocation
option. Paths must be relative to the serverless.yml
. This aligns more with how Serverless Framework handles Lambda function handlers' paths.
The graphql-playground
command which started a graphiql server pointing to the AppSync API has been removed.
Workaround
Use other solutions such as Insomnia, or Postman
v1
offered a way to define some resource such as DataSources, Resolvers, etc. on an existing API (that was previously created using other mechanisms, for example manually). v2
does no longer offer that possibility. It adds complexity, can behave unexpectedly and is probably a bad practice too. Prefer defining your whole API under the same stack.
Workaround
Define your API completely in the same stack. This might require the replacement of the API. You can use custom domains to workaround that, if that's an option.
v1
exported some values to the stack Output by default. This is no longer the case. Instead, prefer using the new exported variables.
Workaround
You still can export those values if you want but you'll have to do it explicitly yourself:
resources:
Outputs:
GraphQlApiUrl:
Value: ${appsync:url}
v1
to v2
. But, please note that there is no guarantee that everything will keep working as expected. Each case is unique and this guide might miss some subtilities that are applicable to you only. It is your responsibility to test your changes and check that they don't break your stack (e.g. in a dev/test environment).
📚 I also strongly advice that you get familiar with the new API first as most changes will probably be obvious and straight forward. Check the documentation for every feature you are using to see if and how they have changed.
💡 v2
now validates the configuration. If anything is wrong, you should get a warning. I recommend that you enable the service configuration validation in your serverless.yml
and set it to error
. Note that this does not guarantee to catch all the issues.
service: my-app
configValidationMode: error
🙋♂️ If you find information that is inaccurate or incomplete in this guide, please open a PR to fix it 🙏.
The first significant change is that you must now define your API under the appSync
attribute directly at the root of your serverless.yml
file, as opposed to placing it under custom
in v1
.
Just move your configuration up one level.
Example:
custom:
appSync:
name: my-api
becomes
appSync:
name: my-api
Some attributes have been renamed for clarity. Here are the most important ones.
- rename
mappingTemplates
toresolvers
- rename
functionConfigurations
topipelineFunctions
- rename
logConfig
tologging
- rename
wafConfig
towaf
DataSources are now defined as a key-value pair object. In v1
, you passed them as an array. Replace the array with a key-value pair object where the key is what you used to have under name
.
Example
dataSources:
- type: AMAZON_DYNAMODB
name: myDatasource
config:
tableName: my-table
becomes:
dataSources:
myDatasource:
type: AMAZON_DYNAMODB
config:
tableName: my-table
Resolvers are now defined as a key-value pair object. In v1
you passed them as an array. Replace the array with a key-value pair object. You can use any value as the key, or use the Type.field
shortcut.
Also rename mappingTemplates
to resolvers
Example:
mappingTemplates:
- type: Query
field: getUser
dataSource: myDataSource
becomes
resolvers:
Query.getUser:
dataSource: myDataSource
Pipeline functions have moved from functionConfigurations
to pipelineFunctions
. Just like Resolvers and datasources, pipelineFunction
expects a key-value pair object. Use the name of the function (name
) as the key.
Example:
functionConfigurations:
- name: myFunction
dataSource: myDataSource
becomes
pipelineFunctions:
myFunction:
dataSource: myDataSource
In v1
you would define the principal authentication provider directly under the appSync
attribute. In v2
it has moved under authentication
.
authenticationType
becomesauthentication.type
- All the specific
*Config
attributes moved toauthentication.config
.
Example:
custom:
appSync:
authenticationType: AMAZON_COGNITO_USER_POOLS
userPoolConfig:
userPoolId: # user pool ID
becomes
appSync:
authentication:
type: AMAZON_COGNITO_USER_POOLS
config:
userPoolId: # user pool ID
Additional auth provider are now under additionalAuthentications
. Items follow the same stucture as authentication
.
Example:
additionalAuthenticationProviders:
- authenticationType: AMAZON_COGNITO_USER_POOLS
userPoolConfig:
userPoolId: # user pool ID
becomes
additionalAuthentications:
- type: AMAZON_COGNITO_USER_POOLS
config:
userPoolId: # user pool ID
If you split your schema into several files, you must use Object extensions on the types that have already been defined. This will often be the case for the Query
, Mutation
and Subscription
types.
example:
# users.graphql
type Query {
getUser(id: ID!): User
}
# users.graphql
type Query {
getPost(id: ID!): Post
}
becomes
# base.graphql
## The Query type must be defined before being extended
type Query
# users.graphql
extend type Query {
getUser(id: ID!): User
}
# users.graphql
extend type Query {
getPost(id: ID!): Post
}
As of September 2021, Amazon Elasticsearch Service is Amazon OpenSearch Service. DataSources of type AMAZON_ELASTICSEARCH
should now use AMAZON_OPENSEARCH_SERVICE
instead.
Example:
dataSources:
- type: AMAZON_ELASTICSEARCH
name: myEndpoint
config:
endpoint: https://abcdefgh.us-east-1.es.amazonaws.com
becomes:
dataSources:
myEndpoint:
type: AMAZON_OPENSEARCH_SERVICE
config:
endpoint: https://abcdefgh.us-east-1.es.amazonaws.com
Due to a backwards-compatibility issue your API keys will get rotated
(changed) upon the first deployment with the v2
version of this plugin. If left unresolved, this will cause your clients that use the keys
to break, until you are able to update them with the newly generated API keys.
If some down time isn't acceptable, there's two ways to mitigate this:
- Add a new temporary API key throught the settings in AWS AppSync Console
- Update all your clients to use this new temporary key
- Deploy your API using the
v2
version of this plugin. The old API keys will get replaced by new ones, but the temporary key will get retained since it's not part of the CloudFormattion stack. - After deployment, take the newly generated keys, and update the clients again.
- Manually delete the temporary key from the AWS AppSync Console
- Find the CloudFormattion resource name of the existing API key(s). You can find the name in the Resources tab of your stack in the CloudFormattion AWS console.
- Add an entry to
Resources.resources
part of theserverless.yml
file, making sure to keep all the configuration (especially the logical ID), exactly the same. - Deploy your API using the
v2
version of this plugin. The old API keys will now get retained because they were manually referenced in theResources
part. - Migrate your clients to the new API keys created by the
v2
plugin - Delete the key from the
Resources