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
81 stars 71 forks source link

Get data from another table in custom mutation #2674

Open jewells07 opened 5 days ago

jewells07 commented 5 days ago

Environment information

System:
  OS: Windows 11 10.0.22631
  CPU: (12) x64 Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz
  Memory: 419.57 MB / 7.91 GB
Binaries:
  Node: 20.14.0 - C:\Program Files\nodejs\node.EXE
  Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD
  npm: 10.7.0 - C:\Program Files\nodejs\npm.CMD
  pnpm: 9.3.0 - ~\AppData\Local\pnpm\pnpm.EXE
NPM Packages:
  @aws-amplify/backend: 1.0.3
  @aws-amplify/backend-cli: 1.0.4
  aws-amplify: 6.3.6
  aws-cdk: 2.145.0
  aws-cdk-lib: 2.145.0
  typescript: 5.4.5
AWS environment variables:
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
  AWS_STS_REGIONAL_ENDPOINTS = regional
No CDK environment variables

Data packages

nuxt-app@ D:\Todo\Todo
├─┬ @aws-amplify/backend-cli@1.0.4
│ └─┬ @aws-amplify/schema-generator@1.0.0
│   └── @aws-amplify/graphql-schema-generator@0.8.6
└─┬ @aws-amplify/backend@1.0.3
  └─┬ @aws-amplify/backend-data@1.0.2
    └── @aws-amplify/data-construct@1.8.5

Description

Im using custom mutation with handler.

In data/resource.ts

CreatingTodo: a.mutation()
  .arguments({
    content: a.string().required(),
  })
  .returns(a.ref('Todo'))
  .handler([
    a.handler.custom({
      entry: './Todo/createTodo.js',
      dataSource: a.ref('Todo'),
    }),
  ])
  .authorization((allow) => [allow.authenticated()]);

In data/Todo/createTodo.js

import { util } from '@aws-appsync/utils';
import * as ddb from '@aws-appsync/utils/dynamodb';

function getUserId(otherTableId) {
  const result = ddb.get({
    key: { id: otherTableId },
    tableName: 'OtherTable',
  });
  console.log('otherTableId', otherTableId);
  if (!result || !result.Item) {
    return 'null';
  }
  return result.Item.userId;
}

export function request(ctx) {
  const userId = getUserId(ctx.otherTable.id);
  const item = {
    ...ctx,
    userId,
    __typename: 'Todo',
  };
  const key = { id: util.autoId() };
  return ddb.put({ key, item });
}

export function response(ctx) {
  return ctx.result;
}

I am encountering an issue where it consistently returns 'null'. How can I retrieve the userId from another table in a custom mutation? Additionally, I attempted to throw an error using return new Error('System not found');, but it did not work. I also tried adding async/await, but it appears to be unsupported. I attempted

export function request(ctx) {
const userId = getUserId(ctx.otherTable.id);
if(!userId)
return util.appendError('Unable to get user ID', 'Invalid', {
      statusCode: 500,
    });
    }
    ....
    } 

export function response(ctx) { 
    if (ctx.error) {
    if (error) {
      return util.appendError(error.message, error.type, result, null);
    }
  }
  return result
  }

but that did not resolve the issue either, which led me to add 'null' as a string.

I have granted the necessary permissions for AppSync logs, but I do not see any logs in CloudWatch. I have explored every possible solution that I am aware of, but the problem persists.

dpilch commented 3 days ago

Which portion of your lambda is returning null? Are you saying the result of the mutation is null or ddb.get is returning null?

jewells07 commented 3 days ago

In this function

function getUserId(otherTableId) {
  const result = ddb.get({
    key: { id: otherTableId },
    tableName: 'OtherTable',
  });
  console.log('otherTableId', otherTableId);
  if (!result || !result.Item) {
    return 'null';
  }
  return result.Item.userId;
}

Actually it is a JavaScript resolver, not lambda

dpilch commented 2 days ago

Ah, makes sense. I don't think @aws-appsync/utils/dynamodb offers the functionality to set the tableName in ddb.get. I don't see this feature documented. I can check with the AppSync team to see if they offer this feature.

jewells07 commented 2 days ago

Yes, I have tried using __typename: 'OtherTable', and it does not work either. How can we perform CRUD operations on the other table within this mutation handler (JavaScript resolver)?

dpilch commented 1 day ago

The resolver can only be attached to a single data source. You will need to use a pipeline resolver to use multiple data sources. https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers-js.html

It would look something like this:

.handler([
  a.handler.custom({
    entry: './OtherTable/getUserID.js',
    dataSource: a.ref('OtherTable'),
  }),
  a.handler.custom({
    entry: './Todo/createTodo.js',
    dataSource: a.ref('Todo'),
  }),
])