Skip to content

DataStore command datastore.save is not inserting the user.username or user.attributes.sub #12400

@magic-fruits

Description

@magic-fruits

Before opening, please confirm:

App Id

i-use-amplify-studio-i-dont-know-which-of-all-arn-to-put-here-sorry

Region

us-east-1

Environment name

Amplify

Figma File Version (if applicable)

No response

Amplify CLI Version

No response

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

No response

What operating system are you using?

No response

Browser type?

No response

Describe the bug

Hi !

How can I make "DataStore" framework insert the user.attribute.sub or user.username into the "owner" field of a GraphQL type?

This guys did that: https://youtu.be/D8gSc7wDRic?si=tmF1f7j-hr5RkJx_

I see that they only used "datastore.save" command, and as you can see, they didnt filled "owner" inside the app. Also, they make the React app compare the user.attributes.sub with the post.owner field and the app automatically recognized that they were the same.

I used that datasore.save command but the "owner" field is "null". I even tryed to set it manually, but it simply doesnt recieve the ID.

My code actually creates the post, but the "owner" field is empty. My process was: I created the Schema in my Code Editor, then I push it to Amplify Studio. It created the types in the "data" section. After that, I enabled the "Enable owner authorization" in Amplify Studio in the "Post" type.

The "Post" type has this Authorization Rules: Authenticated and unauthenticated scopes: Anyone authenticated with API Key can Create, Read, Update, and Delete Product

The "Post" type has: Owner-based scopes:

Enable owner authorization (yes, enabled) Owner-based authorization allows you to tie a data record to a user. Owners can read, create, update, and delete the record.

Allow the owner to perform these operations on their own records: Create, Read, Update, Delete

After that, the "Post" type got an additional field called "owner". Once I pulled the changes to my code editor, there schema.graphql file didnt got the "owner" field, but you can see it in AWS AppSync.

It would be wonderfull if you could help me by telling me where can I add a "console.log" to check or see what is allowing to enter the new "post" but is preventing to put the "user ID" into the "owner" field. Or you can tell me if there is a Hub function, or DataStore.suscribe or similar to identify that. It can be an option if you tell me if the error can be identified with CluodWatch or any other service that reads every answer received and answered by the server.

In the "schema" section of the AWS AppSync console, I clicked on "pipeline" of the "owner" property of the "Product" type. There is this code:

$util.qr($ctx.stash.put("typeName", "Post"))
$util.qr($ctx.stash.put("fieldName", "owner"))
$util.qr($ctx.stash.put("conditions", []))
$util.qr($ctx.stash.put("metadata", {}))
$util.qr($ctx.stash.metadata.put("dataSourceType", "NONE"))
$util.qr($ctx.stash.metadata.put("apiId", "somecode"))
$util.qr($ctx.stash.put("connectionAttributes", {}))

"user" is generating a big JSON object that has the next properties: Session, attributes, authenticationFlowType, client, keyPrefix, pool, preferredMFA, signInUserSession, storage, userDataKey and username", it doesn't have an "isAuthenticated" property.

It has this object (I replaced every sensitive code with "...". If there is no three points "..." its because there wasnt any code or numer)

Session: null
attributes: {sub: '…', email_verified: true, name: '….', phone_number_verified: false, phone_number: '…', …}

authenticationFlowType: "USER_SRP_AUTH"

client: e {endpoint: 'https://cognito-idp.us-....amazonaws.com/', fetchOptions: {…}}

keyPrefix: "CognitoIdentityServiceProvider…."

pool: e {userPoolId: 'us-east-1_...', clientId: '….', client: e, advancedSecurityDataCollectionFlag: true, storage: Storage, …}

preferredMFA: "NOMFA"

signInUserSession: e {idToken: r, refreshToken: e, accessToken: r, clockDrift: 0}accessToken: r {jwtToken: '…', payload: {…}}clockDrift: 0idToken: r {jwtToken: '…', payload: {…}}refreshToken: e {token: '…'}[[Prototype]]: Object

storage: Storage {CognitoIdentityServiceProvider…..LastAuthUser: '…', CognitoIdentityServiceProvider…..idToken: '…', CognitoIdentityServiceProvider…..userData: '{"UserAttributes":[{"Name":"sub","Value":"……Username":"…"}', amplify-signin-with-hostedUI: 'false', ab.storage.messagingSessionStart….: '{"v":…}', …}

userDataKey: "CognitoIdentityServiceProvider…..userData"

username: "…""

That was a sumary of the "user" JSON object, in which I replaced every code with "..."

Would this make more clear what is blocking the fulfillment of the "owner" property? Take into account that the item is succesfully being created, with the version and time filled automatically.

{
    "channel": "datastore",
    "payload": {
        "event": "nonApplicableDataReceived",
        "data": {
            "errors": [
                {
                    "path": [
                        "syncUsers",
                        "items",
                        0,
                        "_version"
                    ],
                    "locations": null,
                    "message": "Cannot return null for non-nullable type: 'Int' within parent 'User' (/syncUsers/items[0]/_version)"
                },
                {
                    "path": [
                        "syncUsers",
                        "items",
                        0,
                        "_lastChangedAt"
                    ],
                    "locations": null,
                    "message": "Cannot return null for non-nullable type: 'AWSTimestamp' within parent 'User' (/syncUsers/items[0]/_lastChangedAt)"
                }
            ],
            "modelName": "User"
        }
    },
    "source": "",
    "patternInfo": []
}

This is the Schema:

type Post @model @auth(rules: [{allow: public}, {allow: owner}]) {
  id: ID!
  content: String!
  blogID: ID @index(name: "byBlog")
  blog: Blog @belongsTo(fields: ["blogID"])
  owner: String  # This one was added lately, and it allows me to insert the "owner" value "manually" (I mean, with the Javascript form in the app), but it keeps being "null" if don´t set it manually.
}

type Blog @model @auth(rules: [{allow: public}, {allow: owner}]) {
  id: ID!
  blog: String!
  posts: [Post] @hasMany(indexName: "byBlog", fields: ["id"])
}

This is my package.json:

{
  "name": "mega-blog",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@aws-amplify/interactions": "^5.2.3",
    "@aws-amplify/ui-react": "^5.0.1",
    "@aws-amplify/ui-react-v1": "npm:@aws-amplify/[email protected]",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "aws-amplify": "^5.3.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-icons": "^4.9.0",
    "react-router-dom": "^6.13.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

This is the code of the two files, "index.js" and "App.js":

index.js

import { Amplify, API, graphqlOperation, Interactions, Auth, AuthModeStrategyType } from 'aws-amplify';
import { withAuthenticator } from '@aws-amplify/ui-react';
import awsconfig from './aws-exports';
Amplify.configure({
  ...awsconfig,
  DataStore: {
    authModeStrategyType: AuthModeStrategyType.MULTI_AUTH
  }
});

App.js

import { Amplify, API, graphqlOperation, Auth } from 'aws-amplify';
import { withAuthenticator } from '@aws-amplify/ui-react';
import { DataStore } from '@aws-amplify/datastore';
import { Post, Blog } from './models';

const App = ({ signOut, user }) => {
  const [post, setPost] = useState('');
  const [blogID, setBlogID] = useState('');
  // AWS Video
  const [currentUser, setCurrentUser] = useState();

  const handleSubmit = async (e) => {
    e.preventDefault();
    async function checkLoginState() {
      try {
        const currentUser = await Auth.currentAuthenticatedUser();
        if (currentUser) {
          console.log('Usuario autenticado con Auth:', currentUser);
          setCurrentUser(currentUser);
        }
      } catch(err) {
        console.log('No se pudo atenticar el usuario:', err);
      }
    };
    checkLoginState(); // It succesfully brings the user JSON object from Cognito

    // Create a new post
    const post = new Post({
      content,
      blogID,
    });
    
    // Save the post to the DataStore
    await DataStore.save(product);

    // Reset the form inputs
    setPost('');
    setBlogID('');
    // Display a success message
    alert('Posted successfully');
  };
..


return..
    <div className="add-post-form">
      <h2>Agregar Post</h2>
      <form onSubmit={handleSubmit}>
        <div className="form-group">
          <label htmlFor="post-post">Post</label>
          <TextField
            id="post-post"
            style={styles.input}
            value={post}
            onChange={(e) => setPost(e.target.value)}
            placeholder="What do you want to share..."
            required
          />
        </div>
        <button type="submit">Add Post</button>
      </form>
    </div>
...

export default withAuthenticator(App);

Expected behavior

The "owner" field of the GraphQL type "Post" should be filled.

Reproduction steps

  1. I activate the form
  2. The form activates the function "handleSubmit"
  3. The function has been tested in two configurations: a) without the "owner" field specified, and b) specifiyng the "owner" field. This is in the variable "post" that is inside the "handleSubmit" function.
  4. The system actually fill the GraphQL Type, but the "owner" field still "null". I checked that in AppSync.

Project Identifier

No response

Additional information

I created the app with the amplify command to create ReactJS apps.
I am using Cloud9
The app is hosted in Amplify
I am using GraphQL shcema
The authetication is with Cognito, and it has activated the "users" section inside the Amplify App.
Actually I dont know which arn do you need from all of that. Sorry for the answer in the arn section.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DataStoreRelated to DataStore categoryquestionGeneral questiontransferredThis issue was transferred from another Amplify project

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions