AWS Messaging & Integration
AppSync
Managed GraphQL service with real-time subscriptions and offline data sync
AWS AppSync is a fully managed GraphQL service that handles the heavy lifting of building production GraphQL APIs, including real-time subscriptions via WebSocket, offline data synchronization for mobile apps, and direct integration with DynamoDB, Lambda, HTTP endpoints, and other AWS services. It eliminates the need to run and manage a GraphQL server, making it a popular choice for mobile and web applications that need real-time data and complex query capabilities.
How AppSync Works: Schema, Resolvers, and Data Sources
AppSync takes a GraphQL schema definition and connects each field resolver to a data source. The schema defines the API contract; resolvers map GraphQL operations to data source calls.
| Component | Description | Example |
|---|---|---|
| Schema | GraphQL SDL definition of types, queries, mutations, subscriptions | type Post { id: ID!, title: String!, author: User } |
| Data source | Backend that resolves data (DynamoDB, Lambda, HTTP, OpenSearch, RDS, EventBridge) | posts-table DynamoDB table |
| Resolver | Mapping between a GraphQL field and a data source operation | getPost query -> DynamoDB GetItem |
| Pipeline resolver | Chain of functions executed in sequence for a single field | Authorize -> fetchFromDB -> transform |
| Direct Lambda resolver | Lambda function called directly without a VTL template | Custom business logic |
# Create an AppSync API
aws appsync create-graphql-api \
--name my-app-api \
--authentication-type API_KEY
# Upload schema
aws appsync start-schema-creation \
--api-id abc123 \
--definition fileb://schema.graphql
# schema.graphql
type Post {
id: ID!
title: String!
content: String!
authorId: ID!
}
type Query {
getPost(id: ID!): Post
listPosts(limit: Int, nextToken: String): PostConnection
}
type Mutation {
createPost(input: CreatePostInput!): Post
updatePost(id: ID!, input: UpdatePostInput!): Post
}
type Subscription {
onCreatePost: Post @aws_subscribe(mutations: ["createPost"])
}Resolver Types: VTL vs JavaScript vs Direct Lambda
AppSync resolvers can be written in three ways, each with different tradeoffs for performance, flexibility, and maintainability.
| Resolver Type | Language | Performance | Use Case |
|---|---|---|---|
| VTL (Velocity Template Language) | Apache Velocity | Fastest - no Lambda cold start | Simple DynamoDB CRUD, HTTP calls |
| JavaScript resolvers | APPSYNC_JS runtime (ES2022 subset) | Fast - runs in AppSync runtime | Logic too complex for VTL, prefer over VTL for new code |
| Direct Lambda resolver | Any Lambda runtime | Slower - Lambda overhead | Complex business logic, third-party SDKs |
| Pipeline resolver | VTL or JS functions chained | Varies | Auth + data fetch + transform in sequence |
// JavaScript resolver for DynamoDB GetItem (APPSYNC_JS runtime)
import { util } from '@aws-appsync/utils';
export function request(ctx) {
return {
operation: 'GetItem',
key: util.dynamodb.toMapValues({ id: ctx.args.id }),
};
}
export function response(ctx) {
if (ctx.error) {
util.error(ctx.error.message, ctx.error.type);
}
return ctx.result;
}AWS recommends using JavaScript resolvers for all new AppSync development instead of VTL. JavaScript resolvers are easier to test locally with the AppSync JavaScript resolver utilities and more readable for most developers.
Real-Time Subscriptions
AppSync subscriptions enable real-time data push over WebSocket using the MQTT over WebSocket protocol. Clients subscribe to mutations, and AppSync automatically pushes results to connected subscribers when those mutations occur.
Subscriptions are defined in the GraphQL schema with the @aws_subscribe directive that links them to one or more mutations. When a mutation fires, AppSync evaluates the subscription resolver to determine what data to push.
| Concept | Description | Notes |
|---|---|---|
| Subscribe | Client opens WebSocket and registers interest in mutation | Client library (Amplify) handles WS management |
| Trigger | A matching mutation is executed | Any client can trigger - pushes to all subscribers |
| Filter | Subscription resolver filters which subscribers receive the event | Filter by user ID, room ID, etc. |
| Connection limit | 1 million concurrent connections per API | Soft limit - can be increased |
| Message size | Up to 240 KB per subscription message | Filter at resolver to reduce payload |
Subscriptions count toward your AppSync connection-minutes pricing. Each connected WebSocket costs money even if no data is flowing. Implement client-side reconnection with backoff and disconnect idle clients to control costs.
Authentication and Authorization Modes
AppSync supports five authentication mechanisms, and a single API can use multiple modes simultaneously. Fine-grained access control can be applied at the field level.
| Auth Mode | When to Use | Notes |
|---|---|---|
| API Key | Public APIs, testing | Expires after 365 days max - not for production user auth |
| Amazon Cognito User Pools | User authentication | JWT-based, integrates with @aws_auth directive for field-level auth |
| AWS IAM | Server-to-server, EC2/Lambda callers | SigV4 signing required |
| OpenID Connect | Third-party IdP (Auth0, Okta) | Standard OIDC JWT |
| Lambda authorizer | Custom auth logic | Lambda returns authorization decision |
# Schema with multi-auth (Cognito for users, IAM for backend)
type Post @aws_cognito_user_pools @aws_iam {
id: ID!
title: String!
# Only visible to admins and the post author
internalNotes: String @aws_auth(cognito_groups: ["Admins"])
}
type Query {
getPost(id: ID!): Post @aws_cognito_user_pools @aws_iam
# Public read - no auth required
listPublishedPosts: [Post] @aws_api_key
}AppSync Pricing
| Operation | Price | Notes |
|---|---|---|
| Query/Mutation operations | $4.00 per million | Charged per API call |
| Subscription connection-minutes | $0.08 per million connection-minutes | Applies to connected WebSocket clients |
| Subscription messages delivered | $2.00 per million | Each push to a subscriber |
| Cache (optional) | $0.038 per ACU-hour | ElastiCache-backed, reduces data source calls |
| Free tier | 250,000 queries/mutations/month free | For 12 months |
AppSync pricing is straightforward for query/mutation heavy apps. The subscription pricing requires careful estimation - a chat app with 10,000 users connected for 8 hours/day costs ~$5.76/day in connection-minutes alone before messages.
Interview Focus Points
- 1What is AppSync and when would you choose it over REST API Gateway + Lambda?
- 2How do AppSync subscriptions work under the hood for real-time data?
- 3What is the difference between VTL resolvers, JavaScript resolvers, and direct Lambda resolvers?
- 4How would you implement fine-grained authorization in AppSync so users can only read their own data?
- 5What is a pipeline resolver and when would you use one?
- 6How does AppSync offline sync work for mobile applications?
- 7What are the authentication options for AppSync and when would you use each?
- 8How would you estimate AppSync costs for a real-time chat application with 50,000 concurrent users?