amplify-category-api icon indicating copy to clipboard operation
amplify-category-api copied to clipboard

Extend v2 pipeline resolvers with a lambda resolver

Open Nxtra opened this issue 3 years ago • 9 comments

Is this feature request related to a new or existing Amplify category?

api

Is this related to another service?

No response

Describe the feature you'd like to request

V2 allows us to extend the Amplify generated resolvers: https://docs.amplify.aws/cli/graphql/custom-business-logic/#override-amplify-generated-resolvers

We can add a vtl template to extend the Auth slot of the pipeline, eg. Query.getMyThings.auth.2.req.vtl

I would like to extend the pipeline by inserting a slot that points to a lambda resolver. I don't think this is possible yet, but ofc i'd be happy to be wrong :)

I'm looking to use this in light of supporting a "Multi-tenant, multi-role" access pattern. And the lambda would be used to check the tenant and the rights of this tenant that I will keep in a table.

Can we extend the generated pipeline with a lambda resolver?

Describe the solution you'd like

For example:

I would like to add something like: Query.getMyThings.auth.2.req.vtl

{
  "version": "2018-05-29",
  "operation": "Invoke",
  "payload": {
      "typeName": "$ctx.stash.get("typeName")",
      "fieldName": "$ctx.stash.get("fieldName")",
      "arguments": $util.toJson($ctx.arguments),
      "identity": $util.toJson($ctx.identity),
      "source": $util.toJson($ctx.source),
      "request": $util.toJson($ctx.request),
      "prev": $util.toJson($ctx.prev)
  }
}

The result of this resolver is then passed to the next resolver/slot in the pipeline.

Describe alternatives you've considered

Writing it in one or multiple vtl resolvers

Additional context

No response

Is this something that you'd be interested in working on?

  • [ ] 👋 I may be able to implement this feature request
  • [ ] ⚠️ This feature might incur a breaking change

Nxtra avatar Jan 20 '22 07:01 Nxtra

Hi, I've been looking for a solution to a similar use case in the last few days as well. However, instead of adding a lambda function as a resolver, I would like to add a request for another DynamoDB table in the pipeline on mutations.

As of today, I've already figured out that Amplify seems to create a new AWS::AppSync::FunctionConfiguration for each slot within the resolver pipeline, unfortunately with a DataSource of "NONE".

I tried to follow along aws-amplify/amplify-cli#3321 to customize my pipeline, and encountered multiple issues:

  • If I build my mutation completely from scratch, I have to write all the *Input types and *.vtl files from scratch as well, which is from my perspective a lot of overhead and not feasible.
  • If I try to replace only the stack for the GQL type, or to change the stack from another stack, amplify push fails because of missing references and parameters.

If there is any solution to the initial question available, I would be very glad to hear about it as well. An appropriate solution from my point of view would be to either tell Amplify which DataSource to use (Lambda, DynamoDB, ...) for additional resolver slots, or if there would be any possibility to manipulate resources of an existing CloudFormation stack with another stack (which I guess will not be working because of how CloudFormation actually works).

Please support by shading some light.

j-mastr avatar Jan 21 '22 14:01 j-mastr

Hi, I've been looking for a solution to a similar use case in the last few days as well. However, instead of adding a lambda function as a resolver, I would like to add a request for another DynamoDB table in the pipeline on mutations.

I'm also trying to find the way to do this. I was able to do this in the previous version (v1) but so far can't find a way to set the data source to another table in one of the slots. I also tried to use other slots, unsuccessfully: https://github.com/aws-amplify/amplify-cli/issues/9584

jk171505 avatar Jan 24 '22 12:01 jk171505

Hi, I've been looking for a solution to a similar use case in the last few days as well. However, instead of adding a lambda function as a resolver, I would like to add a request for another DynamoDB table in the pipeline on mutations.

I'm also trying to find the way to do this. I was able to do this in the previous version (v1) but so far can't find a way to set the data source to another table in one of the slots. I also tried to use other slots, unsuccessfully: aws-amplify/amplify-cli#9584

I am also trying to do this i.e. run an custom lambda or vtl that looks up another table to let me know if the user has access to the requested data in the current table. E.g.

type Conversation {
# run custom function or vtl before this query to see if the current user is part of the conversation by looking up the ConversationParticipants table
      messages: [Message] @hasMany
}

I have tried using a lambda authorizer (https://docs.amplify.aws/lib/graphqlapi/authz/q/platform/js/#aws-lambda) but it requires the client to switch authorization mode just for this query.

I have also tried using cognito groups i.e. 1x group per conversation, but this will hit the 10,000 cognito group limit soon, requires that tokens are regenerated for the user every time they join a new conversation, and generally seems "clunky".

conorw avatar Mar 02 '22 11:03 conorw

I need the same thing and have found a way, but it isn't in the documentation anywhere, so use at your production environment's own risk. All of the slot FunctionConfiguration CDK resources are available to you in the API override.ts file, so you can override a slot's data source with:

export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
  const model = resources.models["YourModel"];
  model.appsyncFunctions[<functionKey>].dataSourceName = "YourOtherTableOrLambdaDataSource";
}

The <functionKey> is constructed as:

<TypeName><FieldName><SlotName><SlotNumber - 1>Function<TypeName><FieldName><SlotName><SlotNumber - 1>Function.AppSyncFunction

For example for a Query resolver listConversations.auth.2, the key is:

QuerylistConversationsauth1FunctionQuerylistConversationsauth1Function.AppSyncFunction

I think I'd want input from the Amplify team if we can rely on this remaining the same. It's a bit messy. These overrides don't work with amplify mock, which is another issue.

pmulka avatar Mar 02 '22 20:03 pmulka

I am also very much interested in this feature. The V2 pipeline with overridable slots are great but not being able to easily override the target to use a lambda function now means I'll likely have to manually wire up a pipeline for the whole thing.

@lazpavel is this by chance misclassified as a V1 feature request?

naedx avatar Jun 18 '22 16:06 naedx

Thanks @pmulka

I've used what you suggested to create a pipeline setup in v2 that's taking a mutation on one DynamoDB table and copying some values in from another table. It'll have to do for now but I'd like something more supported, I'm a bit concerned that the names don't match which might change sometime 'listConversations.auth.2' becomes '...listConversationsauth1...' they seem to be re-indexed.

In case it trips anyone else up I did find behaviour that might cause issues, the pipeline resolvers seem to be deduplicated. You can see this if you look in the console, pipelines share functions.

I had a requirement that my pipeline resolver using a custom dataSourceName was used on multiple types. For instance if you have Mutation.createFoo.postAuth.3.req.vtl and Mutation.createBar.postAuth.3.req.vtl with matching contents as far as I can see only one resolver is actually created, which makes setting up your overrides tricky because you don't know which will be defined and it may change if you add more in the future or change one of the templates.

So that I get consistent behaviour I resolved it by adding the filename as a comment to the top of the vtl files, so each is unique and a new function is created for each pipeline.

Also this should be a graphql-transformer-v2 feature request.

mnightingale avatar Aug 11 '22 14:08 mnightingale

@pmulka what YourOtherTableOrLambdaDataSource should point to if my lambda function name is uniqueNameCheck ?

ggorge-me avatar Sep 06 '23 08:09 ggorge-me

I need the same thing and have found a way, but it isn't in the documentation anywhere, so use at your production environment's own risk. All of the slot FunctionConfiguration CDK resources are available to you in the API override.ts file, so you can override a slot's data source with:

export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
  const model = resources.models["YourModel"];
  model.appsyncFunctions[<functionKey>].dataSourceName = "YourOtherTableOrLambdaDataSource";
}

The <functionKey> is constructed as:

<TypeName><FieldName><SlotName><SlotNumber - 1>Function<TypeName><FieldName><SlotName><SlotNumber - 1>Function.AppSyncFunction

For example for a Query resolver listConversations.auth.2, the key is:

QuerylistConversationsauth1FunctionQuerylistConversationsauth1Function.AppSyncFunction

I think I'd want input from the Amplify team if we can rely on this remaining the same. It's a bit messy. These overrides don't work with amplify mock, which is another issue.

This was working for me with one AppSync function. When I added more functions it stopped working. I followed the exact format, can see the objects when I log them to console, but I consistently get the error where the function is 'undefined' and its dataSourceName is 'undefined'.

I am trying to add a function at the last step of the pipeline resolver that puts the object onto an SQS queue and then I can process it with a lambda or place it where I like. It all works well if the dataSourceName of the function works, but it now consistently sets it to 'NONE_DS' and I can't get any of the workarounds to work anymore. I could really do with this datasource issue to be resolved

dwrynngs avatar Oct 16 '23 15:10 dwrynngs

@pmulka you are a lifesaver. For those who may not know where the overrides come from, just run amplify override api and then look in amplify/backend/api/<yourapi>/override.ts.

MattSenter avatar Aug 20 '24 15:08 MattSenter