By Yan Cui
Since its inception in 2015, GraphQL has enjoyed a meteoric rise in popularity and a huge community has grown around it.
In AppSync, AWS has a GraphQL-as-a-Service offering that makes it easy to build scalable and resilient GraphQL APIs in the cloud. You don’t need to run any servers yourself. Simply configure your GraphQL resolvers, and you have a GraphQL API that can scale to millions of users and offers multi-AZ redundancy out-of-the-box.
Simply put, AppSync is to GraphQL what API Gateway is to REST APIs.
In recent months I have been working extensively with AppSync and have grown to love it. Not only does it make it easy to build scalable GraphQL APIs, but it also makes short work of difficult tasks in API Gateway.
With all else being equal, here are my top five reasons you should consider using AppSync instead of API Gateway for your next project.
Imagine you’re building a CMS app, where super admins can create universities and designate university admins that can administer their own profile.
To implement this, you can use Cognito user groups to control access to the different API endpoints. e.g.
POST /universitiesis only accessible by users in the
Admingroup to create new universities and set up their initial profile.
Post /university/myis only accessibly by users in the
Universitygroup to update their profile.
This is possible with API Gateway, but it takes a lot of work as you can see from the official guide:
In contrast, this is all I need to implement group-based authorization in AppSync.
It’s effortless and self-explanatory.
One of the under-appreciated features of API Gateway is the fact that it can perform request validation for you. Requests that fail the schema validation do not incur costs. It’s a good way to protect yourself against malicious attackers that naively throw junk requests at you. But, of course, this doesn’t stop replay attacks.
However, there’s no support for response validation. Even though you can configure a response model for an endpoint, it’s only used for documentation purposes. You have to implement response validation in your application code. Libraries such as middy has support for this through the validator middleware.
Without response validation, it’s quite easy to accidentally return more data than you intend to.
For example, if you record a user’s
dob in the
User table, should you return it to everyone who views this user’s profile or just the user himself/herself? What about the user’s email?
You might not display these personal data in the UI, but it will still be there in the HTTP response. Anyone with an HTTP proxy can snoop the data.
It’s entirely possible to do a good job of request and response validation with API Gateway. But it’s laborious and API Gateway doesn’t cut you much slack for making mistakes (or simply forgetting to do it).
Now, look at what I need to do in AppSync.
It’s all in the GraphQL type definitions! There is no extra work involved.
What’s not included in the type definition will not be returned. It’s inherent to how GraphQL works. This affords you more time to think about your domain and how best to model it with types, and less time worrying about the mechanics of request and response validation.
Back in re:invent 2018, API Gateway announced support for WebSockets. But once again, it’s anything but easy to use.
You, as the application developer, have to maintain the mapping of the WebSocket connection to users or groups. You do this by implementing Lambda functions that handle the API Gateway
onDisconnect events. When you need to send messages to specific users, you have to find their connection IDs and call the API Gateway Management API to send messages one at a time.
Again, this is a very low-level construct and puts a lot of the heavy-lifting on your shoulders. And it can be very cost-inefficient for implementing group chats or broadcasts.
Imagine if you’re building a sports streaming app, and you want to notify everyone watching Barcelona vs Real Madrid that a goal has gone in. If you have a million viewers for that match, then that translates:
That is, if your Lambda function doesn’t timeout before that, and that you don’t get throttled somewhere along the way!
That said, API Gateway’s WebSockets work fine for those simple use cases where you need to send messages to a small group of users at a time. For example, 1–2–1 private chat, or even group chats where you can limit the size of the group.
However, it is still fairly laborious to implement and forces you to spend a lot of time on the mechanics (the “how”) of socket management rather than what messages to send (the “what”).
By comparison, AppSync subscriptions are a breeze to work with.
And since AppSync announced support for pure WebSockets it can now support millions of connected clients. All these, and you don’t have to manage any connections yourself!
That’s not to say that AppSync subscriptions are without its own rough edges. But more on that in another post.
We touched on the request and response models earlier. Once you have configured the models for your endpoints, they will be included in the API documentation that you can export from the API Gateway console.
This can also be done through the AWS CLI or the AWS SDK. But like so many other things with API Gateway, it’s just not as easy as you’d like…
What about contract-first development? It’s an increasingly popular practice where teams would start by collaborating and agreeing on the API contracts first before they start implementing the API endpoints.
API Gateway allows you to create an API using an openAPI spec.
However, this flow is not supported by many of the tools we use to build APIs with API Gateway and Lambda — e.g. Serverless framework or SAM.
With GraphQL, contract-first development is kinda a given. It’s innate to how people build GraphQL APIs, by starting with defining the types, and queries and mutations. And the resulting
.graphql spec is also self-documenting!
At the time of writing, AppSync has direct (that is, without proxying through a Lambda function) integration with DynamoDB, Lambda, RDS, ElasticSearch and HTTP.
In terms of the number of direct integration with other AWS services, API Gateway wins hands down. There’s no contest here, as API Gateway can integrate with pretty much every other AWS service.
In both cases, API Gateway and AppSync use Apache VTL as the scripting language for these service integrations.
However, in terms of “how” you integrate with other services, the differences between the two are startling.
Based on my experience working on the serverless-apigateway-service-proxy plugin for the Serverless framework, API Gateway service proxies have multiple conventions. Sometimes it integrates with other AWS services through a signed HTTP request to the service’s REST API. Other times you have to write custom VTL code.
In every case, the configuration is fairly complicated as there are a lot of different things you have to configure. Here is a case in point in case you’re wondering.
With AppSync, you always have to write some VTL, which isn’t everyone’s cup of tea. But fortunately, in practice, it’s mostly a case of filling in your bits in a VTL template. And the official documentation does a good job and provides lots of examples you can just copy and paste into your resolver.
On top of that, the AppSync resolver has built-in support for generating pagination tokens for DynamoDB’s
Scan operations. Which obfuscates the internal mechanics of passing the
LastEvaluatedKey from the previous query as the
ExclusiveStartKey for the next query. This is something that many people get wrong and accidentally couples their client-server communication to implementation details in DynamoDB. You can read more about how to do paginations properly here.
Overall, I find that while AppSync has a limited number of direct service integrations, what it has are much better documented and much easier to work with.
So that’s it, here are five glorious reasons to consider using AppSync instead of API Gateway for your next project:
In general, I find that everything I have listed here can be achieved with API Gateway. But in every case, it requires significantly more effort than with AppSync.
On a recent client project, I needed to implement Cognito group-based authorization as well as request and response validation reliably for every API endpoint as we were dealing with sensitive personal data.
After toiling and failing for a week, I decided to pivot to AppSync. And within a few hours, I was able to implement everything we needed and more. As a result, I was able to get the project back on track and focus on solving the meat of the business problem at hand.
Simply put, AppSync is to GraphQL what API Gateway is to REST APIs.