AppSync Merged API – Our real project experience as part of our hackathon

AWS released a new feature for GraphQL APIs in May: Multiple AppSync APIs can be merged into one overall API. Our AI Hackathon gave us the opportunity to test the new Merged API feature in a real-world project.

Why are Merged APIs such a useful feature?

When designing complex software, it is common to break the application into components or microservices. Each component has its own API so that it can be developed and deployed independently. However, when APIs are published or used in front ends, it makes sense to provide an aggregated API with services of all components. This is possible with the new Merged API feature.

How to create a Merged API using AWS CDK?

We first looked at the AppSync documentation in the AWS CDK to see how to create Merged APIs. Unfortunately, the documentation doesn’t include a section on Merged APIs. We checked the feature requests and pull requests on the AWS CDK GitHub project. However, since we did not find any information, we determined that Merged APIs are not currently supported by CDK L2 constructs. To get support for this feature in AWS CDK, we’ve created a feature request in the AWS CDK project.

So how did we create the Merged APIs?

CloudFormation already includes support for Merged APIs. The documentation describes the attributes and resources which are required. Using CDK L1 constructs, we could use these CloudFormation resources to create the Merged API.

First, we created the necessary IAM roles. Currently they don’t follow the principle of least privilege. When Merged APIs are supported in the CDK, this should also be considered.

const role = new Role(this, `merged-api-role-${props.namespace}`, {
  assumedBy: new ServicePrincipal(''),
  roleName: `merged-api-role-${props.namespace}`,
role.addToPolicy(new PolicyStatement({
  resources: ['*'],
  actions: ['appsync:*'],

const cwRole = new Role(this, 'MergedAPICWRole', {
  assumedBy: new ServicePrincipal(''),

cwRole.addToPolicy(new PolicyStatement({
  actions: ['logs:CreateLogGroup',
  resources: [`arn:aws:logs:${cdk.Stack.of(this).region}:${cdk.Stack.of(this).account}:*`],

In the GraphQL API, the attributes apiType and mergedApiExecutionRoleArn are specific to Merged APIs. In addition, logging had to be explicitly configured, which requires more effort than L2 constructs.

const api = new CfnGraphQLApi(this, `merged-api-${props.namespace}`, {
  authenticationType: 'API_KEY',
  additionalAuthenticationProviders: [
      authenticationType: 'AMAZON_COGNITO_USER_POOLS',
      userPoolConfig: {
        userPoolId: props.userPool.userPoolId,
        awsRegion: cdk.Stack.of(this).region,
  apiType: 'MERGED',
  name: cdk.Names.uniqueId(this),
  mergedApiExecutionRoleArn: role.roleArn,
  xrayEnabled: true,
  logConfig: {
    cloudWatchLogsRoleArn: cwRole.roleArn, fieldLogLevel: 'ALL',

Each source API is assigned to the Merged API using a SourceApiAssociation.

new CfnSourceApiAssociation(this, name, {
  sourceApiIdentifier: graphqlApi.apiId,
  mergedApiIdentifier: mergedApi.attrApiId,
  sourceApiAssociationConfig: {
    mergeType: 'AUTO_MERGE',

The first deployment failed. After specifying mergeType: 'AUTO_MERGE', we were able to create the Merged API.

How did we structure our project?

Each component is developed as separate CDK stack. An additional stack called MergedApiStack includes the Merged API. The source APIs are passed to the Merged API Stack using CDK Stack Props.

This allows us to publish a central AppSync API that includes API methods of all components.


Because of the missing CDK L2 constructs, it was difficult to create the Merged API. Otherwise, our experience with the Merged API has been very good. The Merged API is updated directly and allows us to have one central API for our application.

What’s next? We will likely implement an L2 construct to add support for Merged APIs in the AWS CDK. Then our hackathon and community work will also contribute to AWS CDK.

Who to reach out to?
DanielleMatt, Johannes or myself.





Leave a Reply

Your email address will not be published. Required fields are marked *