Simplify AWS Appsync GraphQL API creation with strongly typed Typescript resolvers
sudokar
Posted on July 30, 2023
This post assumes familiarity with AWS Appsync and AWS CDK in general
Introduction
In this post, we'll look into creating an AWS Appsync GraphQL API with TypeScript using cdk-appsync-typescript-resolver AWS CDK construct. This powerful construct simplifies the creation of AWS AppSync resolvers in your CDK project, making it easier and more efficient for developers to work with AppSync.
Complete code is available in Github for reference
Codegen
We can generate Typescript types using GraphQL Code Gen easily.
These types are generated using Codegen CLI command graphql-codegen
for this graphql schema using this codegen config file.
Note: Alternatively, We can use Amplify codegen as well
Resolver in Typescript
We can start writing our resolvers in Typescript using the Codegen generated types and the Appsync's utils package
Lets look at an example resolver. Link to File
import { Context, DynamoDBPutItemRequest, util } from "@aws-appsync/utils";
import { MutationAddTodoArgs, Todo } from "../types/appsync";
export function request(
ctx: Context<MutationAddTodoArgs>
): DynamoDBPutItemRequest {
const { id, ...attrValues } = ctx.args;
return {
operation: "PutItem",
key: {
id: util.dynamodb.toDynamoDB(id),
},
attributeValues: util.dynamodb.toMapValues({
...attrValues,
}),
};
}
export function response(
ctx: Context<MutationAddTodoArgs, object, object, object, Todo>
) {
return ctx.result;
}
This looks a lot better than writing resolvers in Javascript or VTL 😓
We can use types for context, various data sources supported by Appsync and built-in utilities along with generated types for GraphQL schema, which enhances the reliability and maintainability code through static type checking
Transpiling and Bundling
Unfortunately, we can't just sent the resolvers written in Typescript to Appsync yet. Like we transpile Typescirpt to Javascript for AWS Lambda, We will have to do the same for Appsync.
Unfortunately, as of today there is no built-in capability in CDK to do this for us. We will have to do it ourself using Esbuild or something similar, which transpiles and bundles code from Typescript to Javascript.
Using Esbuild's Javascript API, We have a custom CDK construct cdk-appsync-typescript-resolver that will automate the transpilation and bundling process for us.
An example of creating Typescript function using the custom construct AppsyncTypescriptFunction. This abstracts the transpiling and bundling process and setting default properties.
const addTodo = new AppsyncTypescriptFunction(this, "AddTodoFunction", {
name: "addTodo",
api: graphqlApi,
dataSource: dynamoDataSource,
path: path.join(__dirname, "addTodo.ts"),
replaceStrings: {
ENV: "prod",
},
});
JS resolvers doesn't support unit resolvers, supports only pipeline resolvers. When we want to create a unit resolver, we will have to use bit of boilerplate code and settings to make the pipeline resolver as unit resolver.
An added functionality to the construct is to define a property replaceStrings
, which takes a map of from and to strings, used to replace strings in the transpiled and bundled code.
We have another CDK construct TSExpressPipelineResolver to use the AppsyncTypescriptFunction and sets up required boilerplate for us.
An example of using TSExpressPipelineResolver
construct.
new TSExpressPipelineResolver(this, "AddTodoResolver", {
api: graphqlApi,
typeName: "Mutation",
fieldName: "addTodo",
tsFunction: addTodo,
});
Note: We can use instance of
AppsyncTypescriptFunction
construct, which extendsappsync.AppsyncFunction
, in a regularappsync.Resolver
construct too
Deploying the stack
You can find the complete code of this demo on GitHub.
cdk deploy
Tip
Catch invalid syntax (things not supported by Appsync's JS Resolver) while writing resolvers using the Eslint plugin @aws-appsync/eslint-plugin
Conclusion
By using the constructs from cdk-appsync-typescript-resolver, we can now take advantage of static typing and code editor's IntelliSense & inlay hints to make Appsync's resolvers easy and efficient. Generation of types from GraphQL schema makes it even more efficient. And also, With @aws-appsync/eslint-plugin
we can get the benefit of finding invalid syntax while writing code.
Hope this was helpful!
Posted on July 30, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.