From f63578ac92f8bcafeddb4f366e87ee2a5f29ea9a Mon Sep 17 00:00:00 2001 From: Mitchell Valine Date: Mon, 12 Dec 2022 16:08:07 -0800 Subject: [PATCH] fix(appsync): unexpected resolver replacement Fixes an issue where users couldn't control the ID's of appsync resolvers and functions which would cause them to be replaced whenever the data source of the resolver or function was replaced. For resolvers, this could cause a deployment error as cloudformation would attempt to create the new instance of the resolver before deleting the old one throwing 'only one resolver per field' error. Removing `dataSource.createFunction` and `dataSource.createResolver` in favor of the same methods on the `GraphQlApi` construct makes it clear that the parent scope of resolvers and functions is an API and not a data source and therefore wont be replaced when changing data sources. BREAKING CHANGE: removes `createFunction` and `createResolver` from `IDataSource`. Fixes: #13269 --- .../aws-appsync/lib/appsync-function.ts | 10 +-- .../@aws-cdk/aws-appsync/lib/data-source.ts | 24 ------ .../aws-appsync/lib/graphqlapi-base.ts | 22 +++++- .../test/appsync-caching-config.test.ts | 15 ++-- .../aws-appsync/test/appsync-lambda.test.ts | 5 +- .../test/appsync-mapping-template.test.ts | 8 +- .../@aws-cdk/aws-appsync/test/appsync.test.ts | 21 ++++-- .../aws-appsync/test/integ.api-import.ts | 11 ++- .../aws-appsync/test/integ.appsync-lambda.ts | 17 +++-- .../aws-appsync/test/integ.auth-apikey.ts | 6 +- .../test/integ.graphql-elasticsearch.ts | 5 +- .../aws-appsync/test/integ.graphql-iam.ts | 9 ++- .../test/integ.graphql-opensearch.ts | 3 +- .../aws-appsync/test/integ.graphql.ts | 75 ++++++++++++------- 14 files changed, 138 insertions(+), 93 deletions(-) diff --git a/packages/@aws-cdk/aws-appsync/lib/appsync-function.ts b/packages/@aws-cdk/aws-appsync/lib/appsync-function.ts index 7423317d0fa3e..2d1f0129e9768 100644 --- a/packages/@aws-cdk/aws-appsync/lib/appsync-function.ts +++ b/packages/@aws-cdk/aws-appsync/lib/appsync-function.ts @@ -31,6 +31,10 @@ export interface BaseAppsyncFunctionProps { * @default - no response mapping template */ readonly responseMappingTemplate?: MappingTemplate; + /** + * the data source linked to this AppSync Function + */ + readonly dataSource: BaseDataSource; } /** @@ -41,10 +45,6 @@ export interface AppsyncFunctionProps extends BaseAppsyncFunctionProps { * the GraphQL Api linked to this AppSync Function */ readonly api: IGraphqlApi; - /** - * the data source linked to this AppSync Function - */ - readonly dataSource: BaseDataSource; } /** @@ -145,4 +145,4 @@ export class AppsyncFunction extends Resource implements IAppsyncFunction { this.function.addDependsOn(this.dataSource.ds); props.api.addSchemaDependency(this.function); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-appsync/lib/data-source.ts b/packages/@aws-cdk/aws-appsync/lib/data-source.ts index 05268cb469bbc..a327267a31f97 100644 --- a/packages/@aws-cdk/aws-appsync/lib/data-source.ts +++ b/packages/@aws-cdk/aws-appsync/lib/data-source.ts @@ -7,10 +7,8 @@ import { IServerlessCluster } from '@aws-cdk/aws-rds'; import { ISecret } from '@aws-cdk/aws-secretsmanager'; import { IResolvable, Lazy, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; -import { BaseAppsyncFunctionProps, AppsyncFunction } from './appsync-function'; import { CfnDataSource } from './appsync.generated'; import { IGraphqlApi } from './graphqlapi-base'; -import { BaseResolverProps, Resolver } from './resolver'; /** * Base properties for an AppSync datasource @@ -128,28 +126,6 @@ export abstract class BaseDataSource extends Construct { this.name = name; this.api = props.api; } - - /** - * creates a new resolver for this datasource and API using the given properties - */ - public createResolver(props: BaseResolverProps): Resolver { - return new Resolver(this, `${props.typeName}${props.fieldName}Resolver`, { - api: this.api, - dataSource: this, - ...props, - }); - } - - /** - * creates a new appsync function for this datasource and API using the given properties - */ - public createFunction(props: BaseAppsyncFunctionProps): AppsyncFunction { - return new AppsyncFunction(this, `${props.name}Function`, { - api: this.api, - dataSource: this, - ...props, - }); - } } /** diff --git a/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts b/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts index 0737be10c8fc3..4b0efc6820163 100644 --- a/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts +++ b/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts @@ -5,6 +5,7 @@ import { IDomain as IOpenSearchDomain } from '@aws-cdk/aws-opensearchservice'; import { IServerlessCluster } from '@aws-cdk/aws-rds'; import { ISecret } from '@aws-cdk/aws-secretsmanager'; import { CfnResource, IResource, Resource } from '@aws-cdk/core'; +import { AppsyncFunction, BaseAppsyncFunctionProps } from './appsync-function'; import { DynamoDbDataSource, HttpDataSource, LambdaDataSource, NoneDataSource, RdsDataSource, AwsIamConfig, ElasticsearchDataSource, OpenSearchDataSource } from './data-source'; import { Resolver, ExtendedResolverProps } from './resolver'; @@ -134,7 +135,12 @@ export interface IGraphqlApi extends IResource { /** * creates a new resolver for this datasource and API using the given properties */ - createResolver(props: ExtendedResolverProps): Resolver; + createResolver(id: string, props: ExtendedResolverProps): Resolver; + + /** + * creates a new appsync function for this datasource and API using the given properties + */ + createFunction(id: string, props: BaseAppsyncFunctionProps): AppsyncFunction; /** * Add schema dependency if not imported @@ -285,8 +291,18 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { /** * creates a new resolver for this datasource and API using the given properties */ - public createResolver(props: ExtendedResolverProps): Resolver { - return new Resolver(this, `${props.typeName}${props.fieldName}Resolver`, { + public createResolver(id: string, props: ExtendedResolverProps): Resolver { + return new Resolver(this, id, { + api: this, + ...props, + }); + } + + /** + * creates a new appsync function for this datasource and API using the given properties + */ + public createFunction(id: string, props: BaseAppsyncFunctionProps): AppsyncFunction { + return new AppsyncFunction(this, id, { api: this, ...props, }); diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-caching-config.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-caching-config.test.ts index 3537c9c91a3ce..a8469f6a16fd7 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-caching-config.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-caching-config.test.ts @@ -33,7 +33,8 @@ describe('Lambda caching config', () => { // WHEN const lambdaDS = api.addLambdaDataSource('LambdaDS', func); - lambdaDS.createResolver({ + api.createResolver('QueryAllPosts', { + dataSource: lambdaDS, typeName: 'Query', fieldName: 'allPosts', }); @@ -50,7 +51,8 @@ describe('Lambda caching config', () => { // WHEN const lambdaDS = api.addLambdaDataSource('LambdaDS', func); - lambdaDS.createResolver({ + api.createResolver('QueryAllPosts', { + dataSource: lambdaDS, typeName: 'Query', fieldName: 'allPosts', cachingConfig: { @@ -77,7 +79,8 @@ describe('Lambda caching config', () => { // THEN expect(() => { - lambdaDS.createResolver({ + api.createResolver('QueryAllPosts', { + dataSource: lambdaDS, typeName: 'Query', fieldName: 'allPosts', cachingConfig: { @@ -95,7 +98,8 @@ describe('Lambda caching config', () => { // THEN expect(() => { - lambdaDS.createResolver({ + api.createResolver('QueryAllPosts', { + dataSource: lambdaDS, typeName: 'Query', fieldName: 'allPosts', cachingConfig: { @@ -113,7 +117,8 @@ describe('Lambda caching config', () => { // THEN expect(() => { - lambdaDS.createResolver({ + api.createResolver('QueryAllPosts', { + dataSource: lambdaDS, typeName: 'Query', fieldName: 'allPosts', cachingConfig: { diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-lambda.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-lambda.test.ts index 702c85ab928a4..dfaf68d20c162 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-lambda.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-lambda.test.ts @@ -116,7 +116,8 @@ describe('Lambda Data Source configuration', () => { description: 'custom description', }); - ds.createResolver({ + api.createResolver('TestField', { + dataSource: ds, typeName: 'test', fieldName: 'field', }); @@ -164,4 +165,4 @@ describe('adding lambda data source from imported api', () => { ApiId: { 'Fn::GetAtt': ['baseApiCDA4D43A', 'ApiId'] }, }); }); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-mapping-template.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-mapping-template.test.ts index 67ab1b05fd54c..9b3dc8b93d236 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-mapping-template.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-mapping-template.test.ts @@ -34,7 +34,8 @@ describe('Lambda Mapping Templates', () => { // WHEN const lambdaDS = api.addLambdaDataSource('LambdaDS', func); - lambdaDS.createResolver({ + api.createResolver('QueryAllPosts', { + dataSource: lambdaDS, typeName: 'Query', fieldName: 'allPosts', requestMappingTemplate: appsync.MappingTemplate.lambdaRequest(), @@ -52,7 +53,8 @@ describe('Lambda Mapping Templates', () => { // WHEN const lambdaDS = api.addLambdaDataSource('LambdaDS', func); - lambdaDS.createResolver({ + api.createResolver('PostRelatedPosts', { + dataSource: lambdaDS, typeName: 'Post', fieldName: 'relatedPosts', requestMappingTemplate: appsync.MappingTemplate.lambdaRequest('$util.toJson($ctx)', 'BatchInvoke'), @@ -67,4 +69,4 @@ describe('Lambda Mapping Templates', () => { MaxBatchSize: 10, }); }); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/aws-appsync/test/appsync.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync.test.ts index bb64702c47b94..c0e04a3e25045 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync.test.ts @@ -21,13 +21,15 @@ beforeEach(() => { test('appsync should configure pipeline when pipelineConfig has contents', () => { // WHEN const ds = api.addNoneDataSource('none'); - const test1 = ds.createFunction({ + const test1 = api.createFunction('Test1Function', { + dataSource: ds, name: 'test1', }); - const test2 = ds.createFunction({ + const test2 = api.createFunction('Test2Function', { + dataSource: ds, name: 'test2', }); - api.createResolver({ + api.createResolver('TestTest2', { typeName: 'test', fieldName: 'test2', pipelineConfig: [test1, test2], @@ -48,16 +50,19 @@ test('appsync should configure pipeline when pipelineConfig has contents', () => test('appsync should error when creating pipeline resolver with data source', () => { // WHEN const ds = api.addNoneDataSource('none'); - const test1 = ds.createFunction({ + const test1 = api.createFunction('Test1Function', { + dataSource: ds, name: 'test1', }); - const test2 = ds.createFunction({ + const test2 = api.createFunction('Test2Function', { + dataSource: ds, name: 'test2', }); // THEN expect(() => { - ds.createResolver({ + api.createResolver('TestTest2', { + dataSource: ds, typeName: 'test', fieldName: 'test2', pipelineConfig: [test1, test2], @@ -83,7 +88,7 @@ test('appsync should configure resolver as unit when pipelineConfig is empty', ( test('appsync should configure resolver as unit when pipelineConfig is empty array', () => { // WHEN - api.createResolver({ + api.createResolver('TestTest2', { typeName: 'test', fieldName: 'test2', pipelineConfig: [], @@ -237,4 +242,4 @@ test('log retention should not appear when no retention time is specified', () = // THEN Template.fromStack(stack).resourceCountIs('Custom::LogRetention', 0); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/aws-appsync/test/integ.api-import.ts b/packages/@aws-cdk/aws-appsync/test/integ.api-import.ts index 1ccf3228a5dbd..f1c4652732270 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.api-import.ts +++ b/packages/@aws-cdk/aws-appsync/test/integ.api-import.ts @@ -43,14 +43,16 @@ const testTable = new db.Table(stack, 'TestTable', { const testDS = api.addDynamoDbDataSource('ds', testTable); -testDS.createResolver({ +api.createResolver('QueryGetTests', { + dataSource: testDS, typeName: 'Query', fieldName: 'getTests', requestMappingTemplate: appsync.MappingTemplate.dynamoDbScanTable(), responseMappingTemplate: appsync.MappingTemplate.dynamoDbResultList(), }); -testDS.createResolver({ +api.createResolver('MutationAddTest', { + dataSource: testDS, typeName: 'Mutation', fieldName: 'addTest', requestMappingTemplate: appsync.MappingTemplate.dynamoDbPutItem(appsync.PrimaryKey.partition('id').auto(), appsync.Values.projecting('test')), @@ -64,7 +66,8 @@ const api2 = appsync.GraphqlApi.fromGraphqlApiAttributes(stack, 'api2', { const none = api2.addNoneDataSource('none'); -const func = none.createFunction({ +const func = api.createFunction('PipelineFunction', { + dataSource: none, name: 'pipeline_function', requestMappingTemplate: appsync.MappingTemplate.fromString(JSON.stringify({ version: '2017-02-28', @@ -87,4 +90,4 @@ new appsync.Resolver(stack, 'pipeline_resolver', { })), }); -app.synth(); \ No newline at end of file +app.synth(); diff --git a/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.ts b/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.ts index 3a4ec57b07898..1818a06074783 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.ts +++ b/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.ts @@ -47,35 +47,40 @@ const requestPayload = (field: string, { withArgs = false, withSource = false }) }; const responseMappingTemplate = appsync.MappingTemplate.lambdaResult(); -lambdaDS.createResolver({ +api.createResolver('QueryGetPost', { + dataSource: lambdaDS, typeName: 'Query', fieldName: 'getPost', requestMappingTemplate: appsync.MappingTemplate.lambdaRequest(requestPayload('getPost', { withArgs: true })), responseMappingTemplate, }); -lambdaDS.createResolver({ +api.createResolver('QueryAllPosts', { + dataSource: lambdaDS, typeName: 'Query', fieldName: 'allPosts', requestMappingTemplate: appsync.MappingTemplate.lambdaRequest(requestPayload('allPosts', {})), responseMappingTemplate, }); -lambdaDS.createResolver({ +api.createResolver('MutationAddPost', { + dataSource: lambdaDS, typeName: 'Mutation', fieldName: 'addPost', requestMappingTemplate: appsync.MappingTemplate.lambdaRequest(requestPayload('addPost', { withArgs: true })), responseMappingTemplate, }); -lambdaDS.createResolver({ +api.createResolver('PostRelatedPosts', { + dataSource: lambdaDS, typeName: 'Post', fieldName: 'relatedPosts', requestMappingTemplate: appsync.MappingTemplate.lambdaRequest(requestPayload('relatedPosts', { withSource: true }), 'BatchInvoke'), responseMappingTemplate, }); -lambdaDS.createResolver({ +api.createResolver('PostRelatedPostsMaxBatchSize', { + dataSource: lambdaDS, typeName: 'Post', fieldName: 'relatedPostsMaxBatchSize', requestMappingTemplate: appsync.MappingTemplate.lambdaRequest(requestPayload('relatedPostsMaxBatchSize', { withSource: true }), 'BatchInvoke'), @@ -83,4 +88,4 @@ lambdaDS.createResolver({ maxBatchSize: 2, }); -app.synth(); \ No newline at end of file +app.synth(); diff --git a/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.ts b/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.ts index 39462d91e327f..1dbc1948921ba 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.ts +++ b/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.ts @@ -46,14 +46,16 @@ const testTable = new Table(stack, 'TestTable', { const testDS = api.addDynamoDbDataSource('testDataSource', testTable); -testDS.createResolver({ +api.createResolver('QueryGetTests', { + dataSource: testDS, typeName: 'Query', fieldName: 'getTests', requestMappingTemplate: MappingTemplate.dynamoDbScanTable(), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); -testDS.createResolver({ +api.createResolver('MutationAddTest', { + dataSource: testDS, typeName: 'Mutation', fieldName: 'addTest', requestMappingTemplate: MappingTemplate.dynamoDbPutItem(PrimaryKey.partition('id').auto(), Values.projecting('test')), diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.ts b/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.ts index 199dcb6454aeb..31b0f8b79d130 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.ts +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.ts @@ -27,7 +27,8 @@ const api = new appsync.GraphqlApi(stack, 'api', { const ds = api.addElasticsearchDataSource('ds', domain); -ds.createResolver({ +api.createResolver('QueryGetTests', { + dataSource: ds, typeName: 'Query', fieldName: 'getTests', requestMappingTemplate: appsync.MappingTemplate.fromString(JSON.stringify({ @@ -63,4 +64,4 @@ ds.createResolver({ })), }); -app.synth(); \ No newline at end of file +app.synth(); diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.ts b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.ts index 9d2105e923c18..452b1f45b6999 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.ts +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.ts @@ -66,21 +66,24 @@ const testTable = new Table(stack, 'TestTable', { const testDS = api.addDynamoDbDataSource('ds', testTable, { name: 'testDataSource' }); -testDS.createResolver({ +api.createResolver('QueryGetTest', { + dataSource: testDS, typeName: 'Query', fieldName: 'getTest', requestMappingTemplate: MappingTemplate.dynamoDbGetItem('id', 'id'), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); -testDS.createResolver({ +api.createResolver('QueryGetTests', { + dataSource: testDS, typeName: 'Query', fieldName: 'getTests', requestMappingTemplate: MappingTemplate.dynamoDbScanTable(), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); -testDS.createResolver({ +api.createResolver('MutationAddTest', { + dataSource: testDS, typeName: 'Mutation', fieldName: 'addTest', requestMappingTemplate: MappingTemplate.dynamoDbPutItem(PrimaryKey.partition('id').auto(), Values.projecting('test')), diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-opensearch.ts b/packages/@aws-cdk/aws-appsync/test/integ.graphql-opensearch.ts index db7903a6deb5b..fc44222abcfd1 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-opensearch.ts +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-opensearch.ts @@ -27,7 +27,8 @@ const api = new appsync.GraphqlApi(stack, 'api', { const ds = api.addOpenSearchDataSource('ds', domain); -ds.createResolver({ +api.createResolver('QueryGetTests', { + dataSource: ds, typeName: 'Query', fieldName: 'getTests', requestMappingTemplate: appsync.MappingTemplate.fromString(JSON.stringify({ diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql.ts b/packages/@aws-cdk/aws-appsync/test/integ.graphql.ts index 66e4145d51421..c0b2b9e344ff0 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql.ts +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql.ts @@ -53,7 +53,8 @@ const api = new GraphqlApi(stack, 'Api', { const noneDS = api.addNoneDataSource('none', { name: 'None' }); -noneDS.createResolver({ +api.createResolver('QuerygetServiceVersion', { + dataSource: noneDS, typeName: 'Query', fieldName: 'getServiceVersion', requestMappingTemplate: MappingTemplate.fromString(JSON.stringify({ @@ -111,55 +112,64 @@ const customerDS = api.addDynamoDbDataSource('customerDs', customerTable, { name const orderDS = api.addDynamoDbDataSource('orderDs', orderTable, { name: 'Order' }); const paymentDS = api.addDynamoDbDataSource('paymentDs', paymentTable, { name: 'Payment' }); -customerDS.createResolver({ +api.createResolver('QueryGetCustomers', { + dataSource: customerDS, typeName: 'Query', fieldName: 'getCustomers', requestMappingTemplate: MappingTemplate.dynamoDbScanTable(), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); -customerDS.createResolver({ +api.createResolver('QueryGetCustomer', { + dataSource: customerDS, typeName: 'Query', fieldName: 'getCustomer', requestMappingTemplate: MappingTemplate.dynamoDbGetItem('id', 'id'), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); -customerDS.createResolver({ +api.createResolver('QueryGetCusomtersNotConsistent', { + dataSource: customerDS, typeName: 'Query', fieldName: 'getCustomersNotConsistent', requestMappingTemplate: MappingTemplate.dynamoDbScanTable(false), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); -customerDS.createResolver({ +api.createResolver('QueryGetCustomerNotConsistent', { + dataSource: customerDS, typeName: 'Query', fieldName: 'getCustomerNotConsistent', requestMappingTemplate: MappingTemplate.dynamoDbGetItem('id', 'id', false), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); -customerDS.createResolver({ +api.createResolver('QueryGetCustomersConsistent', { + dataSource: customerDS, typeName: 'Query', fieldName: 'getCustomersConsistent', requestMappingTemplate: MappingTemplate.dynamoDbScanTable(true), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); -customerDS.createResolver({ +api.createResolver('QueryGetCustomerConsistent', { + dataSource: customerDS, typeName: 'Query', fieldName: 'getCustomerConsistent', requestMappingTemplate: MappingTemplate.dynamoDbGetItem('id', 'id', true), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); -customerDS.createResolver({ +api.createResolver('MutationAddCustomer', { + dataSource: customerDS, typeName: 'Mutation', fieldName: 'addCustomer', requestMappingTemplate: MappingTemplate.dynamoDbPutItem(PrimaryKey.partition('id').auto(), Values.projecting('customer')), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); -customerDS.createResolver({ +api.createResolver('MutationSaveCustomer', { + dataSource: customerDS, typeName: 'Mutation', fieldName: 'saveCustomer', requestMappingTemplate: MappingTemplate.dynamoDbPutItem(PrimaryKey.partition('id').is('id'), Values.projecting('customer')), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); -customerDS.createResolver({ +api.createResolver('MutationSaveCustomerWithFirstOrder', { + dataSource: customerDS, typeName: 'Mutation', fieldName: 'saveCustomerWithFirstOrder', requestMappingTemplate: MappingTemplate.dynamoDbPutItem( @@ -171,7 +181,8 @@ customerDS.createResolver({ .attribute('referral').is('referral')), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); -customerDS.createResolver({ +api.createResolver('MutationRemoveCustomer', { + dataSource: customerDS, typeName: 'Mutation', fieldName: 'removeCustomer', requestMappingTemplate: MappingTemplate.dynamoDbDeleteItem('id', 'id'), @@ -186,13 +197,15 @@ const ops = [ { suffix: 'Ge', op: KeyCondition.ge }, ]; for (const { suffix, op } of ops) { - orderDS.createResolver({ + api.createResolver('QueryGetCustomerOrders', { + dataSource: orderDS, typeName: 'Query', fieldName: 'getCustomerOrders' + suffix, requestMappingTemplate: MappingTemplate.dynamoDbQuery(op('customer', 'customer')), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); - orderDS.createResolver({ + api.createResolver('QueryGetOrderCustomers', { + dataSource: orderDS, typeName: 'Query', fieldName: 'getOrderCustomers' + suffix, requestMappingTemplate: MappingTemplate.dynamoDbQuery(op('order', 'order'), 'orderIndex'), @@ -200,13 +213,15 @@ for (const { suffix, op } of ops) { }); } for (const { suffix, op } of ops) { - orderDS.createResolver({ + api.createResolver('QueryGetCustomerOrdersNotConsistent', { + dataSource: orderDS, typeName: 'Query', fieldName: 'getCustomerOrdersNotConsistent' + suffix, requestMappingTemplate: MappingTemplate.dynamoDbQuery(op('customer', 'customer'), undefined, false), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); - orderDS.createResolver({ + api.createResolver('QueryGetOrderCustomersNotConsistent', { + dataSource: orderDS, typeName: 'Query', fieldName: 'getOrderCustomersNotConsistent' + suffix, requestMappingTemplate: MappingTemplate.dynamoDbQuery(op('order', 'order'), 'orderIndex', false), @@ -214,41 +229,47 @@ for (const { suffix, op } of ops) { }); } for (const { suffix, op } of ops) { - orderDS.createResolver({ + api.createResolver('QueryGetCustomerOrdersConsistent', { + dataSource: orderDS, typeName: 'Query', fieldName: 'getCustomerOrdersConsistent' + suffix, requestMappingTemplate: MappingTemplate.dynamoDbQuery(op('customer', 'customer'), undefined, true), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); - orderDS.createResolver({ + api.createResolver('QueryGetOrderCustomersConsistent', { + dataSource: orderDS, typeName: 'Query', fieldName: 'getOrderCustomersConsistent' + suffix, requestMappingTemplate: MappingTemplate.dynamoDbQuery(op('order', 'order'), 'orderIndex', true), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); } -orderDS.createResolver({ +api.createResolver('QueryGetCustomerOrdersFilter', { + dataSource: orderDS, typeName: 'Query', fieldName: 'getCustomerOrdersFilter', requestMappingTemplate: MappingTemplate.dynamoDbQuery( KeyCondition.eq('customer', 'customer').and(KeyCondition.beginsWith('order', 'order'))), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); -orderDS.createResolver({ +api.createResolver('QueryGetCustomerOrdersBetween', { + dataSource: orderDS, typeName: 'Query', fieldName: 'getCustomerOrdersBetween', requestMappingTemplate: MappingTemplate.dynamoDbQuery( KeyCondition.eq('customer', 'customer').and(KeyCondition.between('order', 'order1', 'order2'))), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); -orderDS.createResolver({ +api.createResolver('QueryGetOrderCustomersFilter', { + dataSource: orderDS, typeName: 'Query', fieldName: 'getOrderCustomersFilter', requestMappingTemplate: MappingTemplate.dynamoDbQuery( KeyCondition.eq('order', 'order').and(KeyCondition.beginsWith('customer', 'customer'))), responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); -orderDS.createResolver({ +api.createResolver('QueryGetOrderCustomersBetween', { + dataSource: orderDS, typeName: 'Query', fieldName: 'getOrderCustomersBetween', requestMappingTemplate: MappingTemplate.dynamoDbQuery( @@ -256,19 +277,22 @@ orderDS.createResolver({ responseMappingTemplate: MappingTemplate.dynamoDbResultList(), }); -paymentDS.createResolver({ +api.createResolver('QueryGetPayment', { + dataSource: paymentDS, typeName: 'Query', fieldName: 'getPayment', requestMappingTemplate: MappingTemplate.dynamoDbGetItem('id', 'id'), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); -paymentDS.createResolver({ +api.createResolver('QueryGetPaymentConsistent', { + dataSource: paymentDS, typeName: 'Query', fieldName: 'getPaymentConsistent', requestMappingTemplate: MappingTemplate.dynamoDbGetItem('id', 'id', true), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); -paymentDS.createResolver({ +api.createResolver('MutationSavePayment', { + dataSource: paymentDS, typeName: 'Mutation', fieldName: 'savePayment', requestMappingTemplate: MappingTemplate.dynamoDbPutItem(PrimaryKey.partition('id').auto(), Values.projecting('payment')), @@ -277,7 +301,8 @@ paymentDS.createResolver({ const httpDS = api.addHttpDataSource('ds', 'https://aws.amazon.com/', { name: 'http' }); -httpDS.createResolver({ +api.createResolver('MutationDoPostOnAws', { + dataSource: httpDS, typeName: 'Mutation', fieldName: 'doPostOnAws', requestMappingTemplate: MappingTemplate.fromString(`{