Why Serverless GraphQL Is Better with AWS AppSync
The first post was titled The Comforts of GraphQL with AWS AppSync and I made the case for the development of GraphQL applications using the AWS service. In the later posts, I talked about serverless GraphQL with AWS lambda functions via AWS AppSync and the need for monitoring your serverless GraphQL applications.
Since 2018, there have been various developments to the AWS AppSync service that further augment the GraphQL development experience. It is these developments that I will focus on in this post.
Revisiting the Basics
Before we dive into the latest developments of AWS AppSync, it is necessary for us to know exactly what GraphQL is and what does the AWS AppSync service solve for developers building in GraphQL.
GraphQL is a data query and manipulation language API development that allows you to define what data you exactly need. It has three major components:
- Schemas, which are the definitions of all operations
- Data Sources, from where the data is queried
- Resolvers, which act as connecting blocks between the schema operations and data sources.
The structure of GraphQL thus makes it client-specific, which allows the client to decide the data it needs instead of being bombarded with all kinds of fields, irrespective of its relevance. This also leads to a substantial reduction of endpoints needed when building your API. That usually means just having a single endpoint to which all queries are made. A single endpoint, returning client-specific requests is arguably the most noticeable advantage of GraphQL over REST APIs.
AWS AppSync Defined
AWS describes AWS AppSync as a “serverless back-end for mobile, web, and enterprise applications.” So what does this mean exactly?
AWS AppSync allows developers to build GraphQL applications by providing a managed GraphQL service, and aims to simplify the application creation process. AWS AppSync allows developers to define the GraphQL based API, including the schemas, resolvers, and data sources.
Additionally, AppSync provides a comprehensive set of data sources that you can integrate into your GraphQL application, providing business logic in the form of resolvers and Lambda functions. This allows you to build your entire back-end API and application via AppSync. The fact that AppSync allows you to incorporate data sources such as Lambda functions and third-party APIs allows you to connect to practically any source of data that may be required by your application.
After Knowing The Basics
You can see now why AWS AppSync is a viable option for those developing GraphQL applications. Of course, there are other concerns when building production-grade software; such as monitoring, security, scalability, and much more. AWS AppSync addresses these concerns with its extensive feature set, some of which I had introduced in my exploration of the service back in 2018. However, since then, AWS has added to further AWS AppSync capabilities — furthering my case for why I would go with the service, coupled with AWS Lambda, and achieving a serverless GraphQL application.
So let’s take a look at these improvements.
The Expanded AWS AppSync Arsenal
Direct Lambda Resolvers
By far one of the best recent improvements is the capability of using Lambda functions as resolvers. This overcomes the need for defining VTL resolvers in your GraphQL application infrastructure.
To understand the value of this upgrade, we need to first consider how resolvers are traditionally defined in AWS AppSync. As mentioned in the brief summary of the GraphQL basics above, a GraphQL application is made up of schemas, resolvers, and data sources. The job of resolvers is to translate GraphQL requests into a format that is comprehensible by the connected data source. It is then also responsible for translating the response back.
AWS leverages Apache’s Velocity Template Language (VTL) for the purpose of resolvers. VTL itself aims to simplify the usage of dynamic content in web pages. The usage of VTL provides various advantages, some of which are highlighted by Nader Dabit in his piece “Top 9 AWS AppSync Features You Didn’t Know About.”
However, the usage of VTL also adds an unintended technical overhead, because all developers may not be familiar with the syntax. As a result, in my experience, resolver creation usually becomes a bottleneck in the development of GraphQL applications using AWS AppSync, even though AWS provides helpful resolver templates in a bid to speed-up development.
This is where the new improvement in AWS AppSync proves beneficial, because it allows you to use AWS Lambda functions directly as resolvers. Developers now have the choice to bypass the need for VTL resolvers, setting up AWS Lambda functions to handle the mapping of requests between clients and the connected data sources. In fact, developers can also apply hybrid solutions if needed, deploying a combination of VTL and AWS Lambda based resolvers where you see fit.
For more information on the topic, check out the blog post that accompanies the announcement, written by Ed Lima — a senior product manager at AWS. Ed details the benefits and shortcomings of VTL resolvers, provides a comprehensive reasoning for the release of this new feature, and demonstrates how AWS Lambda functions can be put to use as resolvers in AWS AppSync.
Another improvement, announced at the end of 2018, is Pipeline Resolvers. This addition to the set of resolver capabilities enables developers to perform multipart operations in one resolver definition. As mentioned, resolvers are executed by AWS AppSync requests and responses on GraphQL fields, with the usual purpose being the mapping of these requests and responses to the fields.
With the Pipeline capability, these executions can mean having multiple operations triggered by one GraphQL field execution, implemented as separate sequential blocks within the resolver’s “pipeline”. These separate blocks are known as functions and each function can make respective calls to separate data sources.
When using Resolver Pipelines, each resolver consists of ‘Before’ and ‘After’ mapping templates alongside a list of functions. Each function, in turn, possesses request and response mapping templates that manage the interaction of a single data source. Therefore, stacking different functions in the right order allows you to perform more complex resolver operations.
As a result, one of the major benefits of Pipeline resolvers is to enable interaction with various data sources in one field execution. Each function theoretically manages the interaction with a separate data source. Another use-case that is enabled is performing authorization checks, validation and other such operations, prior to the actual mapping of requests and responses to the GraphQL fields — all under the scope of a single resolver.
The feature provides flexibility and empowers developers to perform much-needed complex operations, as per the wide range of use cases when developing GraphQL operations. It is definitely a capability that makes it easier for us to develop with AWS AppSync. For more information on how to build Resolver Pipelines, you can refer to the wonderfully detailed piece written by AWS Solution Architect Josh Kahn.
One of the capabilities that GraphQL and GraphQL services such as AppSync intend to achieve is real-time support for demanding use cases like chat rooms, IoT applications, live social media updates and streaming. This is achieved by the use of subscriptions, which are triggered by mutations performed over the GraphQL fields. Clients subscribed to the GraphQL service then experience real-time updates in what is communicated to users.
Initially, AppSync supported subscriptions by the use of MQTT over WebSockets protocols between the client and service. However, in November 2019, AppSync added support for pure WebSockets. This led to great enhancements that developers could not take advantage of when building GraphQL applications with AppSync, in terms of real-time functional requirements.
The new protocol supports a higher payload that can be sent, which is 240kb vs the measly 128 initially with MQTT over WebSockets. This also means a better connection and broadcast rates. We also get improvements in how we use Cloudwatch metrics in conjunction with our AppSync APIs.
Moreover, we see an improved and more powerful selection set filtering for our GraphQL subscriptions. With MQTT over WebSockets, all subscribed clients would receive the same selection set of mutated payloads. This was because the selection set was defined only by the triggering client of the mutation, and hence all subscribed clients would indiscriminately receive that selection set of the mutation payload. However, with pure WebSockets, each client can now define their own selection set filtering.
Finally, AWS AppSync saw an additional improvement to its real-time capabilities in April of this year. This time AWS released support for generic WebSockets, further enabling developers to choose any WebSocket client of their choice in any programming language. Stephen Johnson, currently the head of worldwide solutions architecture mobile at AWS, wrote a blog post demonstrating how to leverage generic WebSockets by creating a Python WebSocket client.
Keeping Track of AppSync Requests With Thundra
Like in any application, AppSync applications are prone to any type of failures resulting from malicious requests and/or undefined behavior of the resolvers. For this reason, it’s critical to have the correct sense of observability on applications built on AWS AppSync. AWS announced its native AWS X-Ray support for AppSync at the beginning of this year. You need to enable this service one by one for each endpoint.
On the other hand, you may want to have a more holistic understanding of your serverless stack automatically, along with all other resources such as API- Gateway and other Lambda functions. At this point, you can start using Thundra — which automatically gathers all information about AppSync endpoints and links the traces of the requests to the rest of your serverless architecture. It doesn’t require any more instrumentation or effort, it just works seamlessly as soon as you plug Thundra’s AWS CloudFormation integration into your AWS account.
Apart from the three major improvements to AWS AppSync’s feature set that I have described above, there are of course various other enhancements that the service has seen. For example, back in 2018, AppSync was only available in the US East (N. Virginia), US West (Oregon), and US East (Ohio) regions. Now it is available in 18 regions, and this list — just as for every AWS service — is expected to increase. Another such improvement was making 2xlarge instances available, with 317.77Gb of memory to cache GraphQL calls to AWS AppSync APIs.
So a lot more can be expected from AWS AppSync. We will likely see more innovations to not only AWS AppSync, but also other supporting services — or services that can be used in conjunction with AWS AppSync.
When considering the benefits of GraphQL coupled with the features of AppSync and the continuous improvements to the service, I believe that Amazon has revolutionized the way data-driven applications are being developed. There are obviously pros and cons to the case, but from my experience, I would strongly recommend you become accustomed to GraphQL. AWS AppSync is still a relatively new tool, but it is also growing to be a very powerful tool. We can expect new features to continuously roll in, just as they have for the past two years.