Skip to content

feat(gen2-migration): add extended resolvers to product catalog app (DO NOT MERGE TILL KIRO IMPLEMENTS FUNCTIONALITY)#14645

Draft
dgandhi62 wants to merge 15 commits intogen2-migrationfrom
codegen-m3-extendresolvers
Draft

feat(gen2-migration): add extended resolvers to product catalog app (DO NOT MERGE TILL KIRO IMPLEMENTS FUNCTIONALITY)#14645
dgandhi62 wants to merge 15 commits intogen2-migrationfrom
codegen-m3-extendresolvers

Conversation

@dgandhi62
Copy link
Copy Markdown
Contributor

@dgandhi62 dgandhi62 commented Mar 4, 2026

Context

Extended resolvers are functions which we can place at locations within a pipeline resolver. Documentation for the slots to place a function in Amplify gen1 can be found here.

By default, Amplify generates these resolvers:

Example: getProducts

  1. QuerygetProductauth0Function
  2. QuerygetUserpostAuth0Function
  3. QueryGetProductDataResolverFn

Note: The above are the functions inside a default resolver. They also may differ from resolver to resolver. For example,

Example: listUsers

  1. QuerygetUserauth0Function
  2. QuerygetUserpostAuth0Function
  3. QueryListUsersDataResolverFn

As you can see, the default resolvers tend to follow a pattern of placing them within the slots auth0, postAuth0, DataResolver. Furthermore, the only default resolver with a data source is the DataResolverFn.

Example: listUsers
Function: QueryListUsersDataResolverFn
Data Source: UserTable

Function: QuerygetUserauth0Function
Data Source: NONE_DS

Furthermore, any new extended functions added in Amplify Gen1 also have a data source of NONE_DS.

EXAMPLE MIGRATION

Gen1 app product catalog

The following resolver functions are placed inside the resolvers/ directory.
Query.listProducts.postDataLoad.1.res.vtl

#set($items = $ctx.prev.result.items)
#foreach($item in $items)
  #set($stock = 0)
  #if($item.stock)
    #set($stock = $item.stock)
  #end
  #set($price = 0)
  #if($item.price)
    #set($price = $item.price)
  #end
  #set($total = $price * $stock)
  $util.qr($item.put("totalValue", $total))
#end
$util.toJson($ctx.prev.result)

Query.listProducts.postAuth.2.req.vtl

{}

Query.listProducts.postAuth.3.res.vtl

$util.toJson($ctx.prev.result)

Post generate, the resolvers/ directory is copy pasted under amplify/data/ which has the same vtl files as gen1 (no change). In backend.ts, the following code needs to be generated
amplify/backend.ts

// EXTENDING RESOLVERS
const __dirname = dirname(fileURLToPath(import.meta.url));
const resolversDir = join(__dirname, "data/resolvers");

const noneDataSource = backend.data.resources.graphqlApi.addNoneDataSource('none');

// postAuth.2.req.vtl
const postAuth2ReqFunction = new aws_appsync.AppsyncFunction(backend.data.stack, 'QuerylistProductspostAuth2reqvtl', {
  name: 'QuerylistProductspostAuth2reqvtl',
  api: backend.data.resources.graphqlApi,
  dataSource: noneDataSource,
  requestMappingTemplate: aws_appsync.MappingTemplate.fromFile(join(resolversDir, 'Query.listProducts.postAuth.2.req.vtl')),
  responseMappingTemplate: aws_appsync.MappingTemplate.fromString('$util.toJson($ctx.prev.result)'),
});

// postAuth.3.res.vtl
const postAuth3ResFunction = new aws_appsync.AppsyncFunction(backend.data.stack, 'QuerylistProductspostAuth3resvtl', {
  name: 'QuerylistProductspostAuth3resvtl',
  api: backend.data.resources.graphqlApi,
  dataSource: noneDataSource,
  requestMappingTemplate: aws_appsync.MappingTemplate.fromString('$util.toJson({})'),
  responseMappingTemplate: aws_appsync.MappingTemplate.fromFile(join(resolversDir, 'Query.listProducts.postAuth.3.res.vtl')),
});

// postDataLoad.1.res.vtl
const postDataLoad1ResFunction = new aws_appsync.AppsyncFunction(backend.data.stack, 'QuerylistProductspostDataLoad1resvtl', {
  name: 'QuerylistProductspostDataLoad1resvtl',
  api: backend.data.resources.graphqlApi,
  dataSource: noneDataSource,
  requestMappingTemplate: aws_appsync.MappingTemplate.fromString('$util.toJson({})'),
  responseMappingTemplate: aws_appsync.MappingTemplate.fromFile(join(resolversDir, 'Query.listProducts.postDataLoad.1.res.vtl')),
});

const resolver = backend.data.resources.cfnResources.cfnResolvers['Query.listProducts'] as CfnResolver;
const pipelineConfig = resolver.pipelineConfig as CfnResolver.PipelineConfigProperty;
const existingFunctions = pipelineConfig.functions || [];

existingFunctions.splice(2, 0, postAuth2ReqFunction.functionId);
existingFunctions.splice(3, 0, postAuth3ResFunction.functionId);
existingFunctions.splice(5, 0, postDataLoad1ResFunction.functionId);

resolver.pipelineConfig = {
  functions: existingFunctions,
};

Note
Identifying the correct slot order to place the new functions in is crucial. existingFunctions contains the default functions in that resolver and we need to generate indexing according to it. Importantly, refer to the table here for determining the correct indexes. The indexes are also dynamic. By using splice, we are inserting it at the said index. That means that all the functions of it get shifted by +1. This needs to be taken into consideration.

Assumptions to take note of

  1. All existing pipeline resolvers have the same three default function slots
  2. All existing pipeline resolvers have the same type of functions (Query, Mutation, Subscription)
  3. Amplify Gen1 doesn't allow user to configure data sources for extended functions in resolvers and they default to NONE
  4. We also have to ensure that overriden resolver functions are handled correctly since they are both vtl files.

@dgandhi62 dgandhi62 changed the base branch from dev to gen2-migration March 4, 2026 19:27
@dgandhi62 dgandhi62 changed the title feat(gen2-migration): add migration support for extended resolvers feat(gen2-migration): add README for extended resolvers addition to product catalog app Mar 9, 2026
@dgandhi62 dgandhi62 changed the title feat(gen2-migration): add README for extended resolvers addition to product catalog app feat(gen2-migration): add extended resolvers to product catalog app Mar 9, 2026
@dgandhi62 dgandhi62 changed the title feat(gen2-migration): add extended resolvers to product catalog app feat(gen2-migration): add extended resolvers to product catalog app (DO NOT MERGE TILL KIRO IMPLEMENTS FUNCTIONALITY) Mar 9, 2026
@dgandhi62 dgandhi62 marked this pull request as ready for review March 9, 2026 17:54
@dgandhi62 dgandhi62 requested a review from a team as a code owner March 9, 2026 17:54
@dgandhi62 dgandhi62 marked this pull request as draft March 9, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant