Modify Amplify-generated resources
Amplify GraphQL API uses a variety of auto-generated, underlying AWS services and resources. You can customize these underlying resources to optimize the deployed stack for your specific use case.
amplify override api
Run the command above to override Amplify-generated GraphQL API resources including AWS AppSync API, Amazon DynamoDB table, Amazon OpenSearch domain, and more.
The command creates a new overrides.ts
file under amplify/backend/api/<resource-name>/
which provides you the Amplify-generated resources as CDK constructs.
In your CDK project, you can access every underlying resource as an "L2" or "L1" construct. Access the generated resources as L2 constructs via the .resources
property on the returned stack or access the generated resources as L1 constructs using the .resources.cfnResources
property.
const api = new AmplifyGraphQlApi(this, 'api', { <params> });
// Access L2 resources under `.resources`api.resources.tables["Todo"].tableArn;
// Access L1 resources under `.resources.cfnResources`api.resources.cfnResources.cfnGraphqlApi.xrayEnabled = true;Object.values(api.resources.cfnResources.cfnTables).forEach(table => { table.pointInTimeRecoverySpecification = { pointInTimeRecoveryEnabled: false };});
Customize Amplify-generated AppSync GraphQL API resources
Apply all the overrides in the override(...)
function. For example to enable X-Ray tracing for the AppSync GraphQL API:
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.api.GraphQLAPI.xrayEnabled = true;}
You can override the following GraphQL API resources that Amplify generates:
Amplify-generated resource | Description |
---|---|
GraphQLAPI | AWS AppSync GraphQL API resource |
GraphQLAPIDefaultApiKey | API Key resource for the AppSync GraphQL API |
GraphQLAPITransformerSchema | The GraphQL schema that's being deployed. (The output of the GraphQL Transformer) |
GraphQLAPINONEDS | A "none" data source that is used for requests that don't exit the AppSync API |
AmplifyDataStore | The delta sync table used for Amplify DataStore's conflict resolution |
AmplifyDataStoreIAMRole | IAM role used to access the delta sync table for DataStore |
DynamoDBAccess | IAM policy to access the DynamoDB resources from AppSync |
Apply all the customizations on .resources.graphqlApi
or .resources.cfnResources.cfnGraphqlApi
. For example to enable X-Ray tracing for the AppSync GraphQL API:
const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', { definition: AmplifyGraphqlDefinition.fromFiles( path.join(__dirname, 'schema.graphql') ), authorizationModes: { defaultAuthorizationMode: 'API_KEY', apiKeyConfig: { expires: cdk.Duration.days(30) } }});
amplifyApi.resources.cfnResources.cfnGraphqlApi.xrayEnabled = true;
Customize Amplify-generated resources for @model directive
Apply all the overrides in the override(...)
function. Pass in the @model type name into resources.models[...]
to modify the resources generated for that particular @model type. For example, to enable time-to-live on the Todo @model
type's DynamoDB table:
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.models['Todo'].modelDDBTable.timeToLiveSpecification = { attributeName: 'ttl', enabled: true };}
You can override the following @model directive resources that Amplify generates:
Amplify-generated resource | Description |
---|---|
modelStack | The nested stack containing all resources for the @model type |
modelDDBTable | The DynamoDB table containing the data for this @model type |
modelIamRole | IAM role to access the DynamoDB table for this @model type |
modelIamRoleDefaultPolicy | IAM policy to access the delta sync table for this @model type in case DataStore is enabled |
dynamoDBAccess | Default policy associated with the IAM role to access the DynamoDB table for this @model type |
modelDatasource | The AppSync DataSource to representing the DynamoDB table |
invokeLambdaFunction | IAM policy for Lambda-based conflict resolution function |
For example, you can override a model generated DynamoDB table configuration.
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.models['Todo'].modelDatasource.dynamoDbConfig['deltaSyncConfig'][ 'baseTableTtl' ] = '3600';}
Apply all the customizations on .resources.tables["MODEL_NAME"]
or .resources.cfnResources.cfnTables["MODEL_NAME"]
. Pass in the @model type name into .resources.cfnResources.cfnTables["MODEL_NAME"]
to modify the resources generated for that particular @model type. For example, to enable time-to-live on the Todo @model
type's DynamoDB table:
const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', { definition: AmplifyGraphqlDefinition.fromFiles( path.join(__dirname, 'schema.graphql') ), authorizationModes: { defaultAuthorizationMode: 'API_KEY', apiKeyConfig: { expires: cdk.Duration.days(30) } }});
amplifyApi.resources.cfnResources.cfnTables['Todo'].timeToLiveSpecification = { attributeName: 'ttl', enabled: true};
Example - Configure DynamoDB table's billing mode
Set the DynamoDB billing mode for the DynamoDB table. Either "PROVISIONED" or "PAY_PER_REQUEST".
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.models['Post'].modelDDBTable.billingMode = 'PAY_PER_REQUEST';}
const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', { definition: AmplifyGraphqlDefinition.fromFiles( path.join(__dirname, 'schema.graphql') ), authorizationModes: { defaultAuthorizationMode: 'API_KEY', apiKeyConfig: { expires: cdk.Duration.days(30) } }});
amplifyApi.resources.cfnResources.cfnTables['Todo'].billingMode = 'PAY_PER_REQUEST';
Example - Configure provisioned throughput for DynamoDB table or Global Secondary Index
Override the default ProvisionedThroughput provisioned for each @model
table and its Global Secondary Indexes (GSI).
Only valid if the "DynamoDBBillingMode" is set to "PROVISIONED"
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.models['Post'].modelDDBTable.provisionedThroughput = { readCapacityUnits: 5, writeCapacityUnits: 5 };
/** * When billing mode is set to "PROVISIONED", it is necessary to specify `provisionedThroughput` for every Global Secondary Index (GSI) that exists in the table. */
resources.models[ 'Post' ].modelDDBTable.globalSecondaryIndexes[0].provisionedThroughput = { readCapacityUnits: 5, writeCapacityUnits: 5 };}
Example - Enable point-in-time recovery for DynamoDB table
Enable/disable DynamoDB point-in-time recovery for each @model
table.
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.models['Post'].modelDDBTable.pointInTimeRecoverySpecification = { pointInTimeRecoveryEnabled: true };}
const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', { definition: AmplifyGraphqlDefinition.fromFiles( path.join(__dirname, 'schema.graphql') ), authorizationModes: { defaultAuthorizationMode: 'API_KEY', apiKeyConfig: { expires: cdk.Duration.days(30) } }});
amplifyApi.resources.cfnResources.cfnTables[ 'Todo'].pointInTimeRecoverySpecification = { pointInTimeRecoveryEnabled: true};
Customize Amplify-generated resources for @searchable (OpenSearch) directive
Apply all the overrides in the override(...)
function. For example, to modify the OpenSearch instance count:
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig = { ...resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig, instanceCount: 6 };}
You can override the following @searchable directive resources that Amplify generates:
Amplify-generated resource | Description |
---|---|
OpenSearchDataSource | The AppSync data source representing the OpenSearch integration |
OpenSearchAccessIAMRole | IAM role to access OpenSearch domain |
OpenSearchAccessIAMRoleDefaultPolicy | IAM policy to access OpenSearch domain |
OpenSearchDomain | OpenSearch domain containing the @searchable data |
OpenSearchStreamingLambdaIAMRole | IAM role to stream DynamoDB data to OpenSearch domain |
OpenSearchStreamingLambdaIAMRoleDefaultPolicy | IAM policy to stream DynamoDB data to OpenSearch domain |
CloudwatchLogsAccess | IAM policy for granting CloudWatch logs access |
OpenSearchStreamingLambdaFunction | Lambda function to stream DynamoDB data to OpenSearch domain |
OpenSearchModelLambdaMapping | Event source mapping for DynamoDB table stream to Lambda function |
Example - Configure Runtime for Streaming Lambda
You can define the runtime for the @searchable
by setting the runtime value on the function object itself. This can be done to resolve a deprecated runtime in the event that you cannot upgrade your version of the Amplify CLI.
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.opensearch.OpenSearchStreamingLambdaFunction.runtime = 'python3.9';}
Example - Configure OpenSearch Streaming function name
Override the name of the AWS Lambda searchable streaming function
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.opensearch.OpenSearchStreamingLambdaFunction.FunctionName = 'CustomFunctionName';}
Example - Configure OpenSearch instance version
Override the elasticsearchVersion
in the OpenSearch domain created by @searchable
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.opensearch.OpenSearchDomain.elasticsearchVersion = 'OpenSearch_1.3';}
Example - Configure OpenSearch instance type
Override the type of instance launched into the OpenSearch domain created by @searchable
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig = { ...resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig, instanceType: 'm3.medium.elasticsearch' };}
Example - Configure OpenSearch instance count
Override the number of instances launched into the OpenSearch domain created by @searchable
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig = { ...resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig, instanceCount: 2 };}
Example - Configure OpenSearch EBS volume size
Override the amount of disk space allocated to each instance in the OpenSearch domain created by @searchable
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.opensearch.OpenSearchDomain.ebsOptions = { ...resources.opensearch.OpenSearchDomain.ebsOptions, volumeSize: 10 };}
Customize Amplify-generated resources for @predictions directive
Apply all the overrides in the override(...)
function. For example, to add a Path to IAM role that facilitates text translation:
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { resources.predictions.TranslateDataSourceServiceRole.path = '/my/organization/';}
You can override the following @predictions directive resources that Amplify generates:
Amplify-generated resource | Description |
---|---|
RekognitionDataSource | AppSync HTTP data source to connect to Amazon Rekognition service |
RekognitionDataSourceServiceRole | AppSync service role to connect to Amazon Rekognition |
TranslateDataSource | AppSync HTTP data source to connect to Amazon Translate service |
translateTextAccess | IAM policy to connect to Amazon Translate |
LambdaDataSource | AppSync Lambda data source to connect to Amazon Polly |
LambdaDataSourceServiceRole | AppSync service role to connect to Lambda function calling Amazon Polly |
LambdaDataSourceServiceRoleDefaultPolicy | IAM policy for AppSync to connect to Lambda function calling Amazon Polly |
TranslateDataSourceServiceRole | AppSync service role to connect to Amazon Translate |
predictionsLambdaIAMRole | IAM role for Lambda function calling Amazon Polly |
predictionsLambdaFunction | Lambda function calling Amazon Polly |
PredictionsLambdaAccess | IAM policy for Lambda function to access Amazon Polly |
predictionsIAMRole | IAM role to access s3 bucket used by @predictions |
PredictionsStorageAccess | IAM policy to access S3 bucket used by @predictions |
identifyTextAccess | IAM policy to enable Identify Text |
identifyLabelsAccess | IAM policy to enable Identify Text |
Place AppSync Resolvers in Custom-named Stacks
If you have a particularly large GraphQL schema, you may run into issues with too many resources defined in a stack. The most common case where this happens is in the ConnectionStack which contains the resolvers for all of the relational directives in the schema.
Creating a stack mapping does not create an additional root stack for the Amplify environment. All mapped stacks will still be placed under the existing Amplify environment root stack. To map a resolver to a different stack, update <project root>/amplify/api/<api name>/transform.conf.json
with a "StackMapping" block. The StackMapping defines a map from resolver logical ID to stack name.
{ "Version": 5, "ElasticsearchWarning": true, "StackMapping": { "<Resolver logical ID>": "Custom stack name" }}
The easiest way to determine a resolver logical ID is to run amplify api gql-compile
and note the resolver logical ID in the list of Resources in the generated CloudFormation stack. Resolvers for model operations will be of the form <Get | List | Create | Update | Delete><model name>Resolver
. Resolvers for relational directives are of the form <model name><field name>Resolver
.
Example
Given the following schema:
type Blog @model { id: ID! name: String! posts: [Post] @hasMany}
type Post @model { id: ID! title: String! content: String blog: Blog @belongsTo}
To map the CreatePostResolver and the relational resolvers to a stack named 'MyCustomStack', add the following in transform.conf.json
:
"StackMapping": { "CreatePostResolver": "MyCustomStack", "BlogpostsResolver": "MyCustomStack", "PostblogResolver": "MyCustomStack",}