aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.44k stars 2.13k forks source link

Error when creating a data entry that has a relation from Lambda function when authentication is set to custom in model #13969

Closed SanjoSolutions closed 3 weeks ago

SanjoSolutions commented 4 weeks ago

Before opening, please confirm:

JavaScript Framework

Next.js

Amplify APIs

Authentication, GraphQL API, DataStore

Amplify Version

v6

Amplify Categories

auth, function, api

Backend

Amplify Gen 2

Environment information

``` System: OS: Windows 11 10.0.22631 CPU: (32) x64 AMD Ryzen 9 3950X 16-Core Processor Memory: 18.91 GB / 47.92 GB Binaries: Node: 20.16.0 - C:\Program Files\nodejs\node.EXE Yarn: 1.22.19 - C:\Program Files\nodejs\yarn.CMD npm: 10.8.1 - C:\Program Files\nodejs\npm.CMD pnpm: 8.7.6 - C:\Program Files\nodejs\pnpm.CMD Browsers: Chrome: 130.0.6723.70 Edge: Chromium (127.0.2651.74) Internet Explorer: 11.0.22621.3527 npmPackages: %name%: 0.1.0 @ampproject/toolbox-optimizer: undefined () @aws-amplify/backend: ^1.5.1 => 1.5.1 @aws-amplify/backend-cli: ^1.3.0 => 1.3.0 @aws-amplify/ui-react: ^6.5.5 => 6.5.5 @aws-amplify/ui-react-internal: undefined () @aws-amplify/ui-react-server: undefined () @babel/core: undefined () @babel/runtime: 7.22.5 @edge-runtime/cookies: 5.0.0 @edge-runtime/ponyfill: 3.0.0 @edge-runtime/primitives: 5.0.0 @hapi/accept: undefined () @mswjs/interceptors: undefined () @napi-rs/triples: undefined () @next/font: undefined () @opentelemetry/api: undefined () @types/node: ^20 => 20.17.0 @types/react: ^18 => 18.3.12 @types/react-dom: ^18 => 18.3.1 @vercel/nft: undefined () @vercel/og: 0.6.2 acorn: undefined () amphtml-validator: undefined () anser: undefined () arg: undefined () assert: undefined () async-retry: undefined () async-sema: undefined () aws-amplify: ^6.6.6 => 6.6.6 aws-amplify/adapter-core: undefined () aws-amplify/analytics: undefined () aws-amplify/analytics/kinesis: undefined () aws-amplify/analytics/kinesis-firehose: undefined () aws-amplify/analytics/personalize: undefined () aws-amplify/analytics/pinpoint: undefined () aws-amplify/api: undefined () aws-amplify/api/server: undefined () aws-amplify/auth: undefined () aws-amplify/auth/cognito: undefined () aws-amplify/auth/cognito/server: undefined () aws-amplify/auth/enable-oauth-listener: undefined () aws-amplify/auth/server: undefined () aws-amplify/data: undefined () aws-amplify/data/server: undefined () aws-amplify/datastore: undefined () aws-amplify/in-app-messaging: undefined () aws-amplify/in-app-messaging/pinpoint: undefined () aws-amplify/push-notifications: undefined () aws-amplify/push-notifications/pinpoint: undefined () aws-amplify/storage: undefined () aws-amplify/storage/s3: undefined () aws-amplify/storage/s3/server: undefined () aws-amplify/storage/server: undefined () aws-amplify/utils: undefined () aws-cdk: ^2 => 2.163.1 aws-cdk-lib: ^2 => 2.163.1 babel-packages: undefined () browserify-zlib: undefined () browserslist: undefined () buffer: undefined () bytes: undefined () ci-info: undefined () cli-select: undefined () client-only: 0.0.1 commander: undefined () comment-json: undefined () compression: undefined () conf: undefined () constants-browserify: undefined () constructs: ^10.3.0 => 10.4.2 content-disposition: undefined () content-type: undefined () cookie: undefined () cross-spawn: undefined () crypto-browserify: undefined () css.escape: undefined () data-uri-to-buffer: undefined () debug: undefined () devalue: undefined () domain-browser: undefined () edge-runtime: undefined () esbuild: ^0.23.1 => 0.23.1 events: undefined () find-cache-dir: undefined () find-up: undefined () fresh: undefined () get-orientation: undefined () glob: undefined () gzip-size: undefined () http-proxy: undefined () http-proxy-agent: undefined () https-browserify: undefined () https-proxy-agent: undefined () icss-utils: undefined () ignore-loader: undefined () image-size: undefined () is-animated: undefined () is-docker: undefined () is-wsl: undefined () jest-worker: undefined () json5: undefined () jsonwebtoken: undefined () loader-runner: undefined () loader-utils: undefined () lodash.curry: undefined () lru-cache: undefined () mini-css-extract-plugin: undefined () nanoid: undefined () native-url: undefined () neo-async: undefined () next: 14.2.10 => 14.2.10 node-fetch: undefined () node-html-parser: undefined () ora: undefined () os-browserify: undefined () p-limit: undefined () path-browserify: undefined () picomatch: undefined () platform: undefined () postcss-flexbugs-fixes: undefined () postcss-modules-extract-imports: undefined () postcss-modules-local-by-default: undefined () postcss-modules-scope: undefined () postcss-modules-values: undefined () postcss-preset-env: undefined () postcss-safe-parser: undefined () postcss-scss: undefined () postcss-value-parser: undefined () process: undefined () punycode: undefined () querystring-es3: undefined () raw-body: undefined () react: ^18 => 18.3.1 react-builtin: undefined () react-dom: ^18 => 18.3.1 react-dom-builtin: undefined () react-dom-experimental-builtin: undefined () react-experimental-builtin: undefined () react-is: 18.2.0 react-refresh: 0.12.0 react-server-dom-turbopack-builtin: undefined () react-server-dom-turbopack-experimental-builtin: undefined () react-server-dom-webpack-builtin: undefined () react-server-dom-webpack-experimental-builtin: undefined () regenerator-runtime: 0.13.4 sass-loader: undefined () scheduler-builtin: undefined () scheduler-experimental-builtin: undefined () schema-utils: undefined () semver: undefined () send: undefined () server-only: 0.0.1 setimmediate: undefined () shell-quote: undefined () source-map: undefined () source-map08: undefined () stacktrace-parser: undefined () stream-browserify: undefined () stream-http: undefined () string-hash: undefined () string_decoder: undefined () strip-ansi: undefined () superstruct: undefined () tar: undefined () terser: undefined () text-table: undefined () timers-browserify: undefined () tsx: ^4.19.0 => 4.19.1 tty-browserify: undefined () typescript: ^5.6.2 => 5.6.3 (4.4.4, 4.9.5) ua-parser-js: undefined () unistore: undefined () util: undefined () vm-browserify: undefined () watchpack: undefined () web-vitals: undefined () webpack: undefined () webpack-sources: undefined () ws: undefined () zod: undefined () npmGlobalPackages: corepack: 0.28.2 npm: 10.8.1 pnpm: 9.7.0 ```

Describe the bug

In the repro project: when creating a todo from a lambda function, in the returned data the user field is null and the GraphQL client seems to throw an error that required fields of the user are missing.

Expected behavior

The user field is populated with data by the GraphQL API.

Reproduction steps

  1. Install the repro project:

    git clone https://github.com/SanjoSolutions/amplify-create-with-relation-bug-reproduce
    cd amplify-create-with-relation-bug-reproduce
    npm install
    npm run dev-cloud # this runs `ampx sandbox`
    # In another terminal
    npm run dev
  2. Reproduce by opening http://localhost:3000

  3. Check the CloudWatch logs of the createTodo2 function. There should be an error like this:

2024-10-28T18:39:07.572Z    48dafb02-d56a-4182-ac1f-367cf3f3bffe    ERROR   error {
  data: {
    createTodo: {
      content: 'A todo',
      createdAt: '2024-10-28T18:39:07.486Z',
      id: '26a182a1-0869-4183-a94a-d3fcd800e99b',
      updatedAt: '2024-10-28T18:39:07.486Z',
      user: null,
      userId: '24411191-d8d0-4ca3-9536-f6283bb6eede',
      __typename: 'Todo'
    }
  },
  errors: [
    {
      path: [Array],
      locations: null,
      message: "Cannot return null for non-nullable type: 'AWSDateTime' within parent 'User' (/createTodo/user/createdAt)"
    },
    {
      path: [Array],
      locations: null,
      message: "Cannot return null for non-nullable type: 'ID' within parent 'User' (/createTodo/user/id)"
    },
    {
      path: [Array],
      locations: null,
      message: "Cannot return null for non-nullable type: 'String' within parent 'User' (/createTodo/user/name)"
    },
    {
      path: [Array],
      locations: null,
      message: "Cannot return null for non-nullable type: 'AWSDateTime' within parent 'User' (/createTodo/user/updatedAt)"
    }
  ]
}

Code Snippet

// Put your code below this line.
https://github.com/SanjoSolutions/amplify-create-with-relation-bug-reproduce

Log output

``` // Put your logs below this line 2024-10-28T18:39:07.572Z 48dafb02-d56a-4182-ac1f-367cf3f3bffe ERROR error { data: { createTodo: { content: 'A todo', createdAt: '2024-10-28T18:39:07.486Z', id: '26a182a1-0869-4183-a94a-d3fcd800e99b', updatedAt: '2024-10-28T18:39:07.486Z', user: null, userId: '24411191-d8d0-4ca3-9536-f6283bb6eede', __typename: 'Todo' } }, errors: [ { path: [Array], locations: null, message: "Cannot return null for non-nullable type: 'AWSDateTime' within parent 'User' (/createTodo/user/createdAt)" }, { path: [Array], locations: null, message: "Cannot return null for non-nullable type: 'ID' within parent 'User' (/createTodo/user/id)" }, { path: [Array], locations: null, message: "Cannot return null for non-nullable type: 'String' within parent 'User' (/createTodo/user/name)" }, { path: [Array], locations: null, message: "Cannot return null for non-nullable type: 'AWSDateTime' within parent 'User' (/createTodo/user/updatedAt)" } ] } ```

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

chrisbonifacio commented 3 weeks ago

Hi @SanjoSolutions 👋 the relation redaction behavior is not a bug, it is intentional in Gen 2. The way to get around this with graphql queries and mutations created with codegen is to generate them with a max statement depth of 1 so that the selection set only includes top level fields and not nested relational data fields in the mutations. The default is 2.

ampx generate graphql-client-code --statement-max-depth=1

you can also manually remove the user fields from the selection set in this file to test.

https://github.com/SanjoSolutions/amplify-create-with-relation-bug-reproduce/blob/main/amplify/graphql/mutations.ts

SanjoSolutions commented 3 weeks ago

Thanks for the answer.

With a different authentication it seems to return the user. See branch https://github.com/SanjoSolutions/amplify-create-with-relation-bug-reproduce/tree/here-it-works, commit https://github.com/SanjoSolutions/amplify-create-with-relation-bug-reproduce/commit/332dd9066e5c2efe559f23b1df0438dbe09d6659#diff-590c4139982e36911299b1417410e032b5a841ef4b4042513473bcfce4239ce4.

So it's really just intentionally not returning related data when the authentication is set to allow.custom()?

chrisbonifacio commented 3 weeks ago

I'm not sure if the only issue is the authorization rule. The error wasn't that you're unauthorized to access the data, just that the mutation was returning non-nullable fields in the selection set.

The redaction behavior depends on the auth rules and whether it can be determined that it won't change between requests. A custom auth rule means that we can't make that determination, so redaction is enabled.

but that error you got specifically happens when you don't get back fields that are non-nullable, which is just a possible symptom of the redaction behavior but can happen in other instances, especially if you create your own GraphQL queries.

Here's the page where this behavior is explained in a warning:

https://docs.amplify.aws/react/build-a-backend/data/data-modeling/relationships/

chrisbonifacio commented 3 weeks ago

You can test if the redaction behavior is present in the resolver by checking the AppSync console for the mutation's resolver logic. Change the auth rule, redeploy, and check to see if the resolver logic changed.

SanjoSolutions commented 3 weeks ago

Ok, thanks for the explanation.

In the project, where I have experienced this behavior first, I have written a custom GraphQL query which just queries for the fields that were required.