Page updated Jan 16, 2024

Batch put custom resolver

Sometimes you need to create objects in bulk, rather than creating individual objects sequentially and waiting for all the requests to complete.

  1. Define your schema with a custom mutation. The custom mutation should not be deployed to AppSync beforehand if following these steps, the CLI will attach its own resolver preventing you from attaching a custom resource this way.
type Todo @model { id: ID! name: String! description: String } type Mutation { batchCreateTodo(todos: [BatchCreateTodo]): [Todo] } input BatchCreateTodo { id: ID name: String! description: String }
1type Todo @model {
2 id: ID!
3 name: String!
4 description: String
5}
6
7type Mutation {
8 batchCreateTodo(todos: [BatchCreateTodo]): [Todo]
9}
10
11input BatchCreateTodo {
12 id: ID
13 name: String!
14 description: String
15}
  1. Create a custom resource for your resolver and use the following code snippets as a guide to get started

  2. Follow the steps for creating a custom resolver:

amplify add custom
1amplify add custom
? How do you want to define this custom resource? ❯ AWS CDK ? Provide a name for your custom resource ❯ MyCustomResolvers
1? How do you want to define this custom resource?
2❯ AWS CDK
3? Provide a name for your custom resource
4❯ MyCustomResolvers

Next, install the AppSync dependencies for your custom resource:

cd amplify/backend/custom/MyCustomResolvers npm i @aws-cdk/aws-appsync@~1.124.0
1cd amplify/backend/custom/MyCustomResolvers
2npm i @aws-cdk/aws-appsync@~1.124.0

Use the following template as a starting point for your custom CDK stack, the resolvers must be templated with environment references

import * as cdk from '@aws-cdk/core'; import * as AmplifyHelpers from '@aws-amplify/cli-extensibility-helper'; import * as appsync from '@aws-cdk/aws-appsync'; import { AmplifyDependentResourcesAttributes } from '../../types/amplify-dependent-resources-ref'; export class cdkStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps, amplifyResourceProps?: AmplifyHelpers.AmplifyResourceProps) { super(scope, id, props); /* Do not remove - Amplify CLI automatically injects the current deployment environment in this input parameter */ new cdk.CfnParameter(this, 'env', { type: 'String', description: 'Current Amplify CLI env name', }); // Access other Amplify Resources const retVal:AmplifyDependentResourcesAttributes = AmplifyHelpers.addResourceDependency(this, amplifyResourceProps.category, amplifyResourceProps.resourceName, [{ category: "api", resourceName: "<YOUR-API-NAME>" }] ); const requestVTL = ` ## [Start] Initialization default values. ** $util.qr($ctx.stash.put("defaultValues", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) #set($todosArray = []) #foreach($item in \${ctx.args.todos}) $util.qr($item.put("id", $util.defaultIfNullOrBlank($item.id, $util.autoId()))) $util.qr($item.put("createdAt", $util.defaultIfNull($item.createdAt, $createdAt))) $util.qr($item.put("updatedAt", $util.defaultIfNull($item.updatedAt, $createdAt))) $util.qr($item.put("__typename", "Todo")) $util.qr($todosArray.add($util.dynamodb.toMapValues($item))) #end ## [End] Initialization default values. ** $util.toJson( { "version": "2018-05-29", "operation": "BatchPutItem", "tables": { "<TYPE-NAME-HERE>-${apiIdRef}-${envRef}": $todosArray } } ) ` const responseVTL = ` ## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result.data.<TYPE-NAME-HERE>-${apiIdRef}-${envRef}) #end ## [End] ResponseTemplate. ** `; const resolver = new appsync.CfnResolver(this, "custom-resolver", { // apiId: retVal.api.new.GraphQLAPIIdOutput, // https://github.com/aws-amplify/amplify-cli/issues/9391#event-5843293887 // If you use Amplify you can access the parameter via Ref since it's a CDK parameter passed from the root stack. // Previously the ApiId is the variable Name which is wrong , it should be variable value as below apiId: cdk.Fn.ref(retVal.api.replaceWithAPIName.GraphQLAPIIdOutput), fieldName: "querySomething", typeName: "Query", // Query | Mutation | Subscription requestMappingTemplate: requestVTL, responseMappingTemplate: responseVTL, dataSourceName: "TodoTable" // DataSource name }) } }
1import * as cdk from '@aws-cdk/core';
2import * as AmplifyHelpers from '@aws-amplify/cli-extensibility-helper';
3import * as appsync from '@aws-cdk/aws-appsync';
4import { AmplifyDependentResourcesAttributes } from '../../types/amplify-dependent-resources-ref';
5
6export class cdkStack extends cdk.Stack {
7 constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps, amplifyResourceProps?: AmplifyHelpers.AmplifyResourceProps) {
8 super(scope, id, props);
9 /* Do not remove - Amplify CLI automatically injects the current deployment environment in this input parameter */
10 new cdk.CfnParameter(this, 'env', {
11 type: 'String',
12 description: 'Current Amplify CLI env name',
13 });
14
15 // Access other Amplify Resources
16 const retVal:AmplifyDependentResourcesAttributes = AmplifyHelpers.addResourceDependency(this,
17 amplifyResourceProps.category,
18 amplifyResourceProps.resourceName,
19 [{
20 category: "api",
21 resourceName: "<YOUR-API-NAME>"
22 }]
23 );
24
25 const requestVTL = `
26 ## [Start] Initialization default values. **
27 $util.qr($ctx.stash.put("defaultValues", $util.defaultIfNull($ctx.stash.defaultValues, {})))
28 #set( $createdAt = $util.time.nowISO8601() )
29 #set($todosArray = [])
30 #foreach($item in \${ctx.args.todos})
31 $util.qr($item.put("id", $util.defaultIfNullOrBlank($item.id, $util.autoId())))
32 $util.qr($item.put("createdAt", $util.defaultIfNull($item.createdAt, $createdAt)))
33 $util.qr($item.put("updatedAt", $util.defaultIfNull($item.updatedAt, $createdAt)))
34 $util.qr($item.put("__typename", "Todo"))
35 $util.qr($todosArray.add($util.dynamodb.toMapValues($item)))
36 #end
37 ## [End] Initialization default values. **
38 $util.toJson( {
39 "version": "2018-05-29",
40 "operation": "BatchPutItem",
41 "tables": {
42 "<TYPE-NAME-HERE>-${apiIdRef}-${envRef}": $todosArray
43 }
44 } )
45 `
46 const responseVTL = `
47 ## [Start] ResponseTemplate. **
48 #if( $ctx.error )
49 $util.error($ctx.error.message, $ctx.error.type)
50 #else
51 $util.toJson($ctx.result.data.<TYPE-NAME-HERE>-${apiIdRef}-${envRef})
52 #end
53 ## [End] ResponseTemplate. **
54 `;
55
56
57 const resolver = new appsync.CfnResolver(this, "custom-resolver", {
58 // apiId: retVal.api.new.GraphQLAPIIdOutput,
59 // https://github.com/aws-amplify/amplify-cli/issues/9391#event-5843293887
60 // If you use Amplify you can access the parameter via Ref since it's a CDK parameter passed from the root stack.
61 // Previously the ApiId is the variable Name which is wrong , it should be variable value as below
62 apiId: cdk.Fn.ref(retVal.api.replaceWithAPIName.GraphQLAPIIdOutput),
63 fieldName: "querySomething",
64 typeName: "Query", // Query | Mutation | Subscription
65 requestMappingTemplate: requestVTL,
66 responseMappingTemplate: responseVTL,
67 dataSourceName: "TodoTable" // DataSource name
68 })
69 }
70}

By using CloudFormation parameters, you contextualize your custom resolvers to the environment you're working with.

  1. Run amplify push and deploy your API

The full documentation for custom resolvers is available here