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 79 forks source link

@index directive without parameters works in iOS (Swift) app but not web (React) app #1206

Open chrisbonifacio opened 1 year ago

chrisbonifacio commented 1 year ago

How did you install the Amplify CLI?

No response

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

16.13.0

Amplify CLI Version

10.6.2

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

Describe the bug

Following the documentation for adding GSIs to a GraphQL schema: https://docs.amplify.aws/cli/graphql/data-modeling/#configure-a-secondary-index

type RoomSchedule
  @model
  @auth(
    rules: [
      { allow: public }
    ]
  ) {
  id: ID!

  roomID: ID! @index

  startTime: AWSDateTime
}

Deploying a schema with an index without the optional parameters, name or queryField, seems to work in native Swift SDK Amplify app but is causing unexpected behavior in React web app.

In the web app, the GSI is being used by DataStore as the primary key but a primary key already exists.

Adding the name and queryField parameters seems to fix the issue and DataStore uses the correct primary key on the React app.

roomID being considered a primary key (perhaps mistaken for custom primary key?) image

Error thrown during sync process image

While debugging, it seems this if statement is being skipped over because DataStore is not auto-generating a value for the id field.

image

Expected behavior

DataStore uses the correct primary key

Reproduction steps

  1. setup DataStore-enabled GraphQL API and schema with a model including an @index directive, no extra parameters
  2. amplify push
  3. start DataStore in a web app

Project Identifier

92c3dcf409a6854477c23599d6e4a2cc

Log output

``` # Put your logs below this line ```

Additional information

No response

Before submitting, please confirm:

chrisbonifacio commented 1 year ago

I was able to reproduce this issue consistently, marking as a bug.

Interestingly, the first time I save a record, I can see the graphql mutatation sent to AppSync succeed and an id was auto-generated.

  const createRoomSchedule = async () => {
    const roomSchedule = await DataStore.save(
      new RoomSchedule({
        roomID: "456",
        startTime: new Date("2023-01-30T05:30:00").toISOString(),
      })
    );

    console.log("Saved roomSchedule: ", roomSchedule);
  };

Network Activity

Screenshot 2023-01-26 at 4 27 52 PM

Record persisted to local store on first save (ID was autogenerated)

Screenshot 2023-01-26 at 4 28 11 PM

However, in indexedDB, DataStore is still incorrectly using the roomID GSI as the primary key or "key path".

Screenshot 2023-01-26 at 4 32 03 PM

And, running the same DataStore.save code again, replaces the previously "correct" record with this one where the id field is now missing altogether and the roomID is acting as the primary key.

Screenshot 2023-01-26 at 4 28 43 PM
AnilMaktala commented 1 year ago

Hey @chrisbonifacio, can you please re-try after enabling feature flag in cli.json? refer docs here

chrisbonifacio commented 1 year ago

@AnilMaktala unfortunately, that flag was already enabled ☹️ this is still an issue. In talking with @manueliglesias , it seems this schema should not be deployable for a DataStore enabled API to begin with. We may have to throw an error on compilation along with a message on how to correct if @index is in the schema and missing parameters when conflict detection is enabled.

chrisbonifacio commented 1 year ago

For anyone experiencing this issue:

in the mean time you can work around this by adding a name property to the @index directive in your schema.

 type RoomSchedule
   @model
   @auth(
     rules: [
       { allow: public }
     ]
   ) {
   id: ID!
   roomID: ID! @index(name: "byRoom")
 }

You'll need to call amplify push --allow-destructive-graphql-schema-update after making the schema change