aws-amplify / amplify-category-api

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development. This plugin provides functionality for the API category, allowing for the creation and management of GraphQL and REST based backends for your amplify project.
https://docs.amplify.aws/
Apache License 2.0
89 stars 77 forks source link

Dedupe AppSync Functions appears to disregard (or runs before) overridden vtl resolvers #1022

Closed chrisdadej closed 1 year ago

chrisdadej commented 1 year ago

Before opening, please confirm:

How did you install the Amplify CLI?

npm install -g @aws-amplify/cli

If applicable, what version of Node.js are you using?

16.15.0

Amplify CLI Version

10.5.0 (but this has been the case since 8.1.0 which introduced the dedupe feature)

What operating system are you using?

Mac

Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.

No manual changes made

Amplify Categories

api

Amplify Commands

codegen

Describe the bug

Amplify v8.1.0 introduced the following change https://github.com/aws-amplify/amplify-cli/pull/10289 in order to limit the # of resources created in AppSync. It means that 2 or more GraphQL APIs can share the same underlying AppSync Function if their needs are the same. This is determined internally by Amplify by generating a hash over the VTL - which makes perfect sense and generally works as you'd expect...

...until you override one of the generated VTL's for one (or more) of those functions. Rather than the functions having their own separate AppSync Function they continue to use the same one even though the VTL is not the same. My guess is that this happens because the hash is run on the VTL before the overridden VTL is introduced but it could be something else entirely.

Expected behavior

Given the example reproduction steps below, the expectation is that the getUser API uses it's own QueryGetUserAuthFN rather than the shared MutationSaveSomeDataAuthFN once we introduce the /api/<api-name>/resolvers/Query.getUser.auth.req.vtl override.

Reproduction steps

  1. Within the schema.graphql create two (or more) APIs with the same authentication, e.g.
    
    type Mutation {
    saveSomeData(args: SaveSomeDataInput!): Boolean
    @function(name: "my-lambda-${env}")
    @aws_iam
    @aws_cognito_user_pools
    @auth(rules: [
      {allow: public, provider: iam},
      {allow: groups, groups: ["User", "Admin"]}
    ])
    }

type Query { getUser(args: GetUserInput): User @function(name: "another-lambda-${env}") @aws_iam @aws_cognito_user_pools @auth(rules: [ {allow: public, provider: iam}, {allow: groups, groups: ["User", "Admin"]} ]) }


2. After running `amplify api gql-compile && amplify codegen`, as of Amplify v8.1.0 both the `saveSomeData` and `getUser` API's will share a single AppSync Function for the authentication (as the base configuration is the same) and because `deleteSomeData` is "first", the AppSync Function will be `MutationSaveSomeDataAuthFN`. This is expected and working correctly.

4. Override the `getUser` auth by creating your own custom VTL in `/api/<api-name>/resolvers/Query.getUser.auth.req.vtl`. For simplicity, let's set the contents as such (i.e. no authentication):

```vtl
## [Start] Field Authorization Steps. **
#set( $isAuthorized = false )
#if( $util.authType() == "IAM Authorization" )
  #set( $isAuthorized = true )
#end
#if( $util.authType() == "User Pool Authorization" )
  #set( $isAuthorized = true )
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({"version":"2018-05-29","payload":{}})
## [End] Field Authorization Steps. **
  1. Re-run amplify api gql-compile && amplify codegen and note that nothing has changed, both saveSomeData and getUser still share the MutationSaveSomeDataAuthFN function even though their hashes should no longer be the same and therefore getUser should have its own QueryGetUserAuthFN function.

  2. If you change the authentication for getUser e.g.

    type Query {
    getUser(args: GetUserInput): User
    @function(name: "another-lambda-${env}")
    @aws_iam
    @aws_cognito_user_pools
    @auth(rules: [
      {allow: public, provider: iam},
      {allow: groups, groups: ["User", "Admin", "FakeGroupJustToCreateADifferentHash"]}
    ])
    }

and re-run amplify api gql-compile && amplify codegen then getUser correctly has it's own QueryGetUserAuthFN function generated.

GraphQL schema(s)

```graphql # Put schemas below this line type Mutation { saveSomeData(args: SaveSomeDataInput!): Boolean @function(name: "my-lambda-${env}") @aws_iam @aws_cognito_user_pools @auth(rules: [ {allow: public, provider: iam}, {allow: groups, groups: ["User", "Admin"]} ]) } type Query { getUser(args: GetUserInput): User @function(name: "another-lambda-${env}") @aws_iam @aws_cognito_user_pools @auth(rules: [ {allow: public, provider: iam}, {allow: groups, groups: ["User", "Admin"]} ]) } ```

Project Identifier

n/a

Log output

No response

Additional information

Workaround

  1. Do something to change the hash, e.g. as shown above by adding a unique group name and whilst that works, it's a hack rather than a workaround.
phani-srikar commented 1 year ago

This issue is being triaged and tracked here. Please follow that thread for updates.