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

Can't use ref within customType in function returns #2579

Open oe-bayram opened 1 month ago

oe-bayram commented 1 month ago

Environment information

System:
  OS: Windows 11 10.0.22631
Binaries:
  Node: 18.16.0
  Yarn: 1.22.19
  npm: 9.5.1
  pnpm: 9.1.1
NPM Packages:
  @aws-amplify/backend: 1.0.2
  @aws-amplify/backend-cli: 1.0.3
  aws-amplify: 6.3.2
  aws-cdk: 2.142.1
  aws-cdk-lib: 2.142.1
  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

Description

In the return type of my function addCognitoUser I need a customType with a ref to another customType CognitoUser and an error field for handling errors.

However when acessing the ref field user I only get the following properties as suggestion: array, authorization, mutations and required and the following error message:

Property X does not exist on type 'RefType<RefTypeArgFactory<"CognitoUser">, never, undefined>'.

This is the definition of my function:

addCognitoUser: a
    .query()
    .arguments({
      email: a.string().required(),
      temporaryPassword: a.string().required(),
      groups: a.string().required().array().required(),
      salutation: a.string().required(),
      firstName: a.string().required(),
      lastName: a.string().required(),
      phone: a.string().required(),
      username: a.string().required(),
      userID: a.id().required(),
    })
    .returns(
      a.customType({
        user: a.ref("CognitoUser"), // CognitoUser is a custom type
        error: a.string(),
      }),
    )
    .authorization((allow) => [allow.groups(["Admin"])])
    .handler(a.handler.function(addCognitoUser)),
ykethan commented 1 month ago

Hey👋 thanks for raising this! I'm going to transfer this over to our API repository for better assistance 🙂

chrisbonifacio commented 1 month ago

Hi @oe-bayram , thanks for raising this issue. Could you also share the CognitoUser type in your schema so we can better reproduce the issue?

Also, regarding the error message:

Property X does not exist on type 'RefType<RefTypeArgFactory<"CognitoUser">, never, undefined>'.

is that the actual error message? As in, is X an actual field name on the CognitoUser customType or was that a redaction?

Lastly, can you confirm when exactly the error is occuring? Is it when modifying the schema and the sandbox attempts to redeploy? Or is it at runtime when you try to use the query?

We tried to reproduce with the same schema but the sandbox was able to redeploy.

Another point of failure might be the lambda handler if you are importing and trying use the returnType like so:

type AddCognitoUser = Schema["addCognitoUser"]["returnType"]

If so, could you please share the lambda handler code as well?

oe-bayram commented 3 weeks ago

The CognitoUser type has the following schema:

CognitoUserGroup: a.customType({
  GroupName: a.string().required(),
  Description: a.string().required(),
  UserPoolId: a.string().required(),
  CreationDate: a.string().required(),
  LastModifiedDate: a.string().required(),
  Precedence: a.integer().required(),
}),

CognitoUser: a.customType({
  username: a.string().required(),
  createDate: a.string().required(),
  enabled: a.boolean().required(),
  userStatus: a.string().required(),
  emailVerified: a.boolean().required(),
  gender: a.string().required(),
  firstName: a.string().required(),
  lastName: a.string().required(),
  phone: a.string().required(),
  fax: a.string().required(),
  email: a.string().required(),
  groups: a.ref("CognitoUserGroup").required().array().required(),
}),

The deployment runs successfully. However, during development when using the client to run the query and trying to access the response fields, a TypeScript error occurs indicating that the type User does not have a property X.

const { data, errors } = await client.queries.addCognitoUser({
...
});

// eg. can't access firstName here as `user` has only props `array`, `authorization`, `mutations` and `required`.
const firstName = data?.user.firstName;

The function handler for addCognitoUser looks like this:

export const handler: Schema["addCognitoUser"]["functionHandler"] = async (
  event,
) => {
  const { user, error } = await addNewUser(event.arguments);

  return {
    user: user as any, // Using `any` here as TypeScript complains otherwise about the return type of the handler
    error,
  };
};
chrisbonifacio commented 4 days ago

Hi @oe-bayram apologies for the delay. Are you still running into this issue?

In trying to reproduce this issue it seems that user in your function handler is being returned from a addNewUser function but the logic and return type is not clear from the shared code. If you're still experiencing this issue, please share the addNewUser function as well.