Creating a GraphQL API using AWS AppSync and CDK

How to create a GraphQL CRUD backend using an IaC approach in a timely, effective and flexible manner.

Pedro Henrique Corado
5 min readMar 24, 2024

As Software Engineers, we sometimes need to provide quick solutions to trivial problems. When that happens, we face the challenge of delivering what the product or the business needs in a timely manner while not creating tech debts, which this kind of situation often leads us to.

In this session, an effective and flexible solution for building an entire GraphQL API with all the CRUDs needed will be introduced, keeping the developer in control of CI/CD, security, and other aspects using AWS CDK. The goal is to code as little as possible and spend the energy on functions or features that MUST be customized.

TLDR: Clone the tutorial repo, customize the GraphQL Schema and deploy.

What we’re going to build?

Solution Diagram — Simple and effective!

We will use AWS AppSync to create a complete GraphQL CRUD backend. Under the hood, GraphQL queries and mutations, Resolvers functions, DynamoDB tables, and an API Endpoint will be created without intervention. However, you will be able to access all outputs and use them in other stacks of your project.

Initializing the project

To get started, we’ll use the AWS CDK CLI to bootstrap our project. If you need to install it, you can find the instructions here.

npx cdk init sample-app --language typescript

Installing AWS Amplify libraries

We need to use an L3 CDK Construct that wraps the behaviour of the Amplify GraphQL Transformer and enables support to the Amplify GraphQL Directives.

npm install @aws-amplify/graphql-api-construct

Designing the GraphQL Schema

Then, we are going to design our GraphQL Schema. This schema was created for demonstration purposes only. I’ve used AWS AppSync Directives like @model, @auth, @belongsTo and @hasMany. Further details can be found here.

type Movie @model(subscriptions: null) @auth(rules: [{ allow: public }]) {
id: ID!
name: String!
year: Int!
rating: Float!
poster: String!
tags: [String]
studio: Studio! @belongsTo
}

type Studio @model(subscriptions: null) @auth(rules: [{ allow: public }]) {
id: ID!
name: String!
movies: [Movie] @hasMany
}

Placing the schema in the lib folder

The schema.graphql file should be placed in the lib folder. If you want to put it into another folder, please update the stack definition introduced in the next step.

Writing the CDK stack

Modify the CDK Stack class to create the AWS AppSync API. This transformer has many options and customizations; the complete documentation is here.

export class AwsCdkAppsyncStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);

const amplifyApi = new AmplifyGraphqlApi(this, 'aws-cdk-appsync-api', {
definition: AmplifyGraphqlDefinition.fromFiles(
path.join(__dirname, 'schema.graphql')
),
authorizationModes: {
defaultAuthorizationMode: 'API_KEY',
apiKeyConfig: {
expires: Duration.days(30),
},
},
});
}
}

Deploying

We’re set. Now, we can deploy our project. Before completing this step, you should configure your AWS CLI. The instructions are here.

cdk deploy

Check out the Output values in the terminal. We’ll need them in the next step.

Outputs:
AwsCdkAppsyncStack.amplifyApiModelSchemaS3Uri =
AwsCdkAppsyncStack.awsAppsyncApiEndpoint =
AwsCdkAppsyncStack.awsAppsyncApiId =
AwsCdkAppsyncStack.awsAppsyncApiKey =
AwsCdkAppsyncStack.awsAppsyncAuthenticationType = API_KEY
AwsCdkAppsyncStack.awsAppsyncRegion = us-east-1
Stack ARN:

You can see all generated queries, mutations, VTL functions, DynamoDB tables over the AWS console:

DynamoDB Tables
Resolvers
Queries and Mutations

Running Mutations & Queries

Let’s test what we’ve just created! Set up your favourite GraphQL client to access the brand-new API. From the step above, you should get awsAppsyncApiEndpoint and awsAppsyncApiKey.

If you don’t have a favourite GrapQL client, use GraphiQL, Postman, or the AWS Console (AWS AppSync > APIs > your-api-name > Queries).

If you are using a post request, set the API Key correctly. Like this:

curl --location '{awsAppsyncApiEndpoint}' \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: {awsAppsyncApiKey}' \

Testing

  • Create a Movie
mutation CreateMovieMutation(
$name: String!,
$poster: String!,
$rating: Float!,
$year: Int!,
$studioMoviesId: ID,
$tags: [String]) {
createMovie(
input: {
name: $name,
poster: $poster,
rating: $rating,
year: $year,
studioMoviesId: $studioMoviesId,
tags: $tags}
) {
id
}
}
Example of a Create Mutation
  • Query a Movie
query GetMovieQuery($id: ID!) {
getMovie(id: $id) {
id
name
year
rating
poster
tags
studio {
name
}
}
}
Example of a Get Query

Conclusion

As demonstrated here, building a complete GraphQL API with all the CRUD mutations is a nice to have in a Software Engineer’s tool belt. The main effort here should be designing a well-shaped GraphQL schema with the product team rather than writing lambda functions and VTL files from scratch. By using IaC (AWS CDK), you are able to keep the solution compliant with all the company’s devops rules and security policies. At the same time, you should spend a few hours building a complete backend solution and putting it alive. You can find the code from this tutorial on my GitHub.

Going further

In the next sessions, we will discuss options for controlling authorization using AWS Cognito User Pools and API Keys.

--

--

Pedro Henrique Corado

Software Engineer since 1999, 2X AWS Architect Certified, music addicted, Fluminense-BR fan 🇭🇺, and enjoy Ontario, Canada 🇨🇦.