amplify-codegen icon indicating copy to clipboard operation
amplify-codegen copied to clipboard

Wrong type for codegen models for items with AWSJSON in their fields (DataStore)

Open thecodehen opened this issue 3 years ago • 5 comments

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

Authentication, GraphQL API, DataStore, Storage

Amplify Categories

No response

Environment information

# Put output below this line
  System:
    OS: macOS 12.2.1
    CPU: (8) x64 Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz
    Memory: 1.01 GB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.13.1 - ~/.nvm/versions/node/v16.13.1/bin/node
    npm: 7.19.0 - {REDACTED}/node_modules/.bin/npm
    Watchman: 2022.02.14.00 - /usr/local/bin/watchman
  npmPackages:
    -: 0.0.1 => 0.0.1 
    @aws-amplify/ui-react: ^2.8.0 => 2.8.0 
    @aws-amplify/ui-react-internal:  undefined ()
    @aws-amplify/ui-react-legacy:  undefined ()
    @material-ui/core: ^4.12.2 => 4.12.2 
    @material-ui/icons: ^4.11.2 => 4.11.2 
    @testing-library/jest-dom: ^5.14.1 => 5.14.1 
    @testing-library/react: ^11.2.7 => 11.2.7 
    @testing-library/user-event: ^12.8.3 => 12.8.3 
    @types/react: ^17.0.19 => 17.0.19 
    @types/react-dom: ^17.0.9 => 17.0.9 
    @types/react-router-dom: ^5.3.3 => 5.3.3 
    @uiw/react-md-editor: ^3.6.3 => 3.6.3 
    aws-amplify: ^4.3.14 => 4.3.14 
    bootstrap: ^4.6.0 => 4.6.0 
    g: ^2.0.1 => 2.0.1 
    npm: ^7.19.0 => 7.19.0 
    react: ^17.0.2 => 17.0.2 
    react-app-rewired: ^2.1.8 => 2.1.8 
    react-dom: ^17.0.2 => 17.0.2 
    react-lorem-ipsum: ^1.4.9 => 1.4.9 
    react-markdown: ^7.0.1 => 7.0.1 
    react-player: ^2.9.0 => 2.9.0 
    react-router-dom: ^5.2.0 => 5.2.0 
    react-scripts: 4.0.3 => 4.0.3 
    rehype-katex: ^5.0.0 => 5.0.0 
    remark-math: ^5.1.0 => 5.1.0 
    source-map-loader: ^3.0.0 => 3.0.0 
    ts-loader: ^9.2.5 => 9.2.5 
    typescript: ^4.3.5 => 4.3.5 
    uuid: ^8.3.2 => 8.3.2 (3.3.2, 3.4.0)
    web-vitals: ^1.1.2 => 1.1.2 
  npmGlobalPackages:
    @aws-amplify/cli: 7.6.22
    aws-cdk: 2.3.0
    corepack: 0.10.0
    npm: 8.1.2


Describe the bug

When getting an item that has AWSJSON in its fields, DataStore returns a Typescript JSON object for the AWSJSON field instead of a string.

However, the codegen models for Typescript label the field as a string instead of an object. Therefore, this causes issues since Typescript thinks an object is a string.

Expected behavior

The codegen models should have labeled AWSJSON fields as objects instead of strings.

Reproduction steps

(Not tested, hypothesized reproduction steps)

  1. Create Schema with a type that has AWSJSON in one of its fields.
  2. Use DataStore to query for an item of the above type
  3. Log typeof type.field and it should return object instead of string.

Code Snippet

# GraphQL Schema
type Post @model @auth(rules: [
    {allow: private, operations: [read]},
]) {
  id: ID!
  content: AWSJSON
}
// Put your code below this line.
import Amplify from 'aws-amplify';
import * as models from 'src/models';

// ...

const posts = await Amplify.DataStore.query(models.Post);
console.log(typeof posts[0].content);
// Should give you "object"
console.log("a" + posts[0].content);
// Should give you "a[Object object]"
console.log(posts[0].content);
// Should give you a JSON object

// src/models/index.d.ts
export declare class Post {
  readonly id: string;
  readonly content?: string; // <--- this gives errors
  readonly createdAt?: string;
  readonly updatedAt?: string;
  // ...
}

Log output

// Put your logs below this line


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

Workarounds

Use // @ts-ignore when assigning the value to another place and act as it is a JSON object.

Other symptoms

May cause A cross-origin error was thrown. React doesn’t have access to the actual error object in development. in React.

May be related to GraphQL Transformer V2 issues: https://github.com/aws-amplify/amplify-adminui/issues/426

thecodehen avatar Mar 06 '22 17:03 thecodehen

Hi @thecodehen 👋 Thanks for raising this issue. It has been transferred to the CLI repo because it seems the issue has to do with codegen rather than the JS Library and/or DataStore.

chrisbonifacio avatar Mar 07 '22 18:03 chrisbonifacio

Thanks! Another thing to add is that the data returned by API.GraphQL used to be in string form, but I'm not sure whether it's because of DataStore or the upgrade from Transformer V1 to V2.

thecodehen avatar Mar 07 '22 19:03 thecodehen

Hi @thecodehen , thanks for bringing this to our attention. I was able to reproduce the issue. The same behavior is also observed for the types generated using amplify codegen types . We will have a fix for this issue in upcoming releases, once we verify the expected behavior.

phani-srikar avatar Mar 14 '22 17:03 phani-srikar

Just to add some additional metadata, I created a test app to look at the different ways this surfaces. Note: I'm on amplify CLI version 9.2.1 and didn't explore the dimension of past releases. https://github.com/alharris-at/codegen-396-repro

My findings:

API Interface

Write only works when serialize to a string, so if we want to support object as an input type, it'll require library updates I think.

Retrieve always returns a string-ified version of the AWSJSON object.

Due to the simplicity of the API category interface, this isn't wholly surprising, there's no significant serde layer in API, so we expect correctly serialized values as inputs to graphql, and return serialized outputs for most things, i.e. the layer speaks JSON, and is therefore restricted by its limitations (this includes, dates, times, objects represented as strings in the backend, etc.).

From my perspective this is reasonable behavior, as it is inline with the rest of the behavior here.

DataStore Interface

Write works for either a serialized version of the AWSJSON object, or an object directly as well. Looks like the library is marshalling back to string as necessary.

Read always returns a parsed version of the AWSJSON object, not a string.

Updating the generated types to use object rather than string just works, suggesting that the DataStore use-case can be fixed purely in the codegen layer.

Because of the split behavior in datastore (write string, return object), we should make some change here to normalize.

I took a look at the behavior of AWSDateTime, to see how other serialized types are behaving today. They appear to be represented in the model as a string as well (not necessarily "correct" behavior) on both read and write.

While I'm not sure if that's the right long-term behavior for our system, it means that DataStore reads of AWSJSON is the only really out-of-band behavior here, and everything else appears consistent, if not ideal.

I'll raise this with the team, and propose a next step in this issue after that.

alharris-at avatar Aug 29 '22 23:08 alharris-at

Hi, Is there a plan to deal with this bug (as it makes the entire AWSJSON type difficult to use with TypeScript). Or is there a recommended workaround that doesn't involve manually hacking the Schema after every pull? Thank you

melchiorb avatar Aug 16 '23 08:08 melchiorb