AWS AppSync, simply said API Gateway for GraphQL since it allows you to connect your GraphQL schema to different data sources like RDS, DynamoDB, Lambda, HTTP endpoint etc.
We are using AppSync in our Purple Apps to power application APIs.
Learn more in Purple Stack API docs.
The AppSync Subscriptions
First we were excited to see that AppSync supports GraphQL subscriptions. But the excitement went down slightly when we discovered that they are tightly coupled with mutations.
This feature seems to be nice when working on some super simple CRUD system, but when you start building a bigger application which has a lot of business logic hidden in asynchronous background processes like Step Functions, it starts to fall short.
We solved that problem by creating dummy mutations with pass-through lambda resolvers which can be invoked only by IAM users.
Later on we discovered "local resolvers" which can do the same job with no need for invoking lambda function.
Along the way we've stumbled upon some specific AppSync behaviours which are not obvious at first sight and information about them is "hidden" deep down in the documentation within complex sentences.
1. Subscription arguments are matched against the mutation response fields, not against the mutation arguments.
Nowhere in the documentation is it said how exactly the subscription arguments matching magic works. It’s unclear whether the matching is done against the mutation arguments or the mutation response fields.
2. The subscription response must be optional
I don't understand exactly why, but the subscription response must be optional. AppSync allows you to successfully save the schema with a required subscription response, but when you try to connect to the subscription from a frontend client, it starts throwing some shallow error which doesn't explicitly tell you that subscription responses must be optional. And then you spend several hours trying to figure out where the problem is.
3. A subscription message contains only the fields which were requested by the mutation - other fields will be null
After some time I've found out that this is explained in three big paragraphs in the docs.
The point is that even though your lambda resolver is returning values for all the mutation fields, an AppSync subscription is only seeing the mutation fields which were selected in the mutation request. This is probably caused by the fact that resolver doesn't have to return values for fields which are not requested in the mutation request.
4. If the filtering field is not specified in the mutation response, the subscription is not fired
This feature could be inferred from the first point, but still it's an important thing to realize.
In this case the subscription doesn't get fired because the mutation is not requesting
fieldA which is used for filtering in the subscription data.
Even though your lambda resolver also returned a value for
fieldA, it's not going to work because matching happens after selecting the requested fields - not before.
5. The subscription resolver is optional - but it can be used for authorization
When I was testing subscriptions, I asked myself, "what happens if I create a lambda resolver for the subscription?" So I tried and I discovered that the subscription resolver is called every time before a new subscription connection is established.
It seems like the subscription resolver is meant for authorization, because it doesn't really matter what you return as an output for the resolver. Only thing that matters is if the resolver function succeeds or fails. If it succeeds, a connection is established; if it fails, an error is sent to the frontend.
AppSync is a nice and useful service but it still has some space for improvements and new features which we are definitely looking forward to.
Hopefully this article made your life easier in case you've been struggling with AppSync and you have a better overview of what you can do with it.
With ❤️ made in Brno.
If you have any ideas or you see something incorrect in the article, let me know on firstname.lastname@example.org 🙂