Recently I’ve been developing a web app for my friends and decided to go with AppSync (well at first I went with my old stack but then switched to AppSync). There are a couple of things I learned along the way and it seems only logical to share those things with the world.
The app will be released soon and it consists of your typical queries to access data including paginated results and mutations to alter/create/delete records. Besides that, it includes some subscriptions that are vital to the overall business logic of the application. It also relies on dynamoDB triggers for when some data are deleted and more actions are required on the server side.
I was looking into changing my usual stack for a while and getting into the whole serverless world. The idea looked very promising considering the server provider at that time wasn’t allowing me to use Docker containers which complicated separation of environments. Furthermore, this app has huge potential to grow and scalability is in some ways already handled by AWS.
Before jumping on serverless hype train I was using my default stack consisting of MySQL/PostgreSQL, react, a GraphQL server using apollo-server-express. All usually hosted in your standard VPS.
The first thing I noticed (and immediately fell in love with) was the fact that I can write everything in the yaml file to define all that I need. Maybe this is a great opportunity to mention that I went with the serverless framework and not with amplify. I first wanted to try amplify-cli but it felt short when I wanted to introduce SSR on one specific route and also set the caching policy of this route. To my knowledge amplify-cli is not yet there when it comes to advanced configurations.
The serverless framework allowed me to specify everything in yaml files and deploy them with one command. Everything from AppSync gateway trough databases, functions, SSR entry point, CloudFront settings, lambda@edge functions, domains, and an SSL certificate. This is really practical and with some plugins easy to set up.
Another nice thing was the possibility to specify the direct mapping from query/mutation to the dynamoDB table. Lots of times I didn’t have to write the necessary code to do simple operations and instead, I just copied some VTL templates and altered them. Chaining of them is now possible so the operations can be somewhat more complex. When I had no other option but to write lambda functions, usually, I had all the environmental variables available to do write the logic of the operation quickly.
I also like that the AppSync client is basically an Apollo client so this was very familiar territory for me. Writing subscriptions became easier too, I just had to specify which mutation should trigger an update for the clients.
The community around serverless is so huge that when I wanted a plugin to take care of a certificate for my domain, or one that can bundle my assets and upload them to the s3 bucket, I usually found them within a minute.
Plugins I used:
The fact that AppSync takes away the need for me to understand and set up a whole lot of stuff around the server architecture makes my life easier and is a nice argument to why serverless is being so popular lately and why it will tempt more people to give it a try.
For instance, trying to notify your subscribers outside of AppSync world is deemed almost impossible. You need to search and find a way how to basically fire a mutation to which you previously mapped your subscription in schema. This code is not provided in any library but luckily there are snippets and articles floating around that will help you with this task.
Dynamodb is also not ideal, I kinda knew that because I worked with firebase before and I knew what I should expect from the NoSQL database and how to architecture it so it fits all my needs. But it still took me a while to wrap around my head around the range and hash keys. In the end if you accept what it offers and that you’ll probably have to do streams to Amazon ES for advanced searches, DynamoDB will be just enough.
VTL files can do quick and easy tasks take you almost no time at all, but debugging is almost impossible. From what I found your only option is raising error from the response to read them.
VTL files can do quick and easy tasks and writing them takes almost no time at all, but debugging is almost impossible. From what I found your only option is raising an error from the response to read them. And if you need to do something more complicated, well you either need to go and write chained VTL functions (which is even harder to debug) or just write the lambda function. Most of my issues would be simply fixed if VTL would support transactional operations (sadly it’s just not possible right now)
Lambda@edge is perfect to go around CloudFront limitations but guess what, they can get stuck easily when you want to remove them and will just be there in your dashboard (unless you decide to delete your account).
Speaking of CloudFront, why it doesn’t support the brotli compression? I would really love not to put more logic into my lambda function so I can just respond with compressed files.
Offline support is also another painful struggle. To some extent, there is a plugin to support offline AppSync and help you spin up a local dybamoDB instance, but the AppSync emulator doesn’t support CloudFormation syntax. Also, cognito doesn’t provide any way for you to run it locally. In the end, I usually just deployed the stack to the dev environment and connected to it.
Last but not least, AppSync or better to say AWS, provides such a nice and complex way to do authentication and authorization that at some point I was considering switching to custom jwt solution. When you finally do your roles and groups and assign permissions to them, you will find out there is no straight forward way to refresh the credentials including the new group on the client. You need to do something like this to get it done.
The huge point for serverless naysayers is the fact that you get stuck in a single ecosystem and then you’re left on the mercy of that ecosystems maintainers/owners. While this is hugely true, the point when you realize you need to get away from it because of cost or technology limitations is usually the point where you would pay for a huge refactor anyway. While this is not ideal, it’s not as bad of a nightmare as everybody says it is when it comes to quickly spinning up projects. There are also alternatives that I plan investigating with the new project (looking at your kubeless)
I wouldn’t be able to get a good insight into the serverless world without doing this project. I’ve chosen AppSync because it covered the basics I needed and while there were a couple of hiccups on the way, in the end, it delivered,