aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.43k stars 2.12k forks source link

User is unauthorized to query sync**** with auth mode API_KEY. No data could be returned. #8738

Closed chris-lee-code closed 3 years ago

chris-lee-code commented 3 years ago

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

DataStore

Amplify Categories

auth

Environment information

``` # Put output below this line System: OS: macOS 11.5.1 CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz Memory: 2.38 GB / 8.00 GB Shell: 5.8 - /bin/zsh Binaries: Node: 16.2.0 - /usr/local/bin/node Yarn: 1.22.11 - ~/Documents/******/node_modules/.bin/yarn npm: 7.15.0 - ~/node_modules/.bin/npm Browsers: Chrome: 92.0.4515.131 Safari: 14.1.2 npmPackages: @ampproject/toolbox-optimizer: undefined () @atlaskit/spinner: ^15.0.11 => 15.0.11 @atlaskit/spinner/constants: undefined () @atlaskit/spinner/spinner: undefined () @atlaskit/spinner/types: undefined () @aws-amplify/cli: ^5.3.0 => 5.3.0 @aws-amplify/ui-react: ^1.2.8 => 1.2.8 @babel/core: undefined () @fortawesome/fontawesome-svg-core: ^1.2.36 => 1.2.36 @fortawesome/free-brands-svg-icons: ^5.15.4 => 5.15.4 @fortawesome/free-solid-svg-icons: ^5.15.4 => 5.15.4 @fortawesome/react-fontawesome: ^0.1.15 => 0.1.15 @fullcalendar/common: ^5.9.0 => 5.9.0 @fullcalendar/core: 5.9.0 => 5.9.0 @fullcalendar/daygrid: ^5.9.0 => 5.9.0 @fullcalendar/interaction: 5.9.0 => 5.9.0 @fullcalendar/react: ^5.9.0 => 5.9.0 @next/bundle-analyzer: ^11.0.1 => 11.0.1 @types/googlemaps: 3.39.13 => 3.39.13 @types/markerclustererplus: 2.1.33 => 2.1.33 @types/react: 17.0.16 => 17.0.16 @zeit/next-css: 1.0.1 => 1.0.1 @zeit/next-sass: 1.0.1 => 1.0.1 amazon-cognito-identity-js: ^5.0.6 => 5.0.6 (4.6.3) amphtml-validator: undefined () arg: undefined () async-retry: undefined () async-sema: undefined () aws-amplify: ^4.2.2 => 4.2.2 aws-amplify-react: ^5.0.8 => 5.0.8 bfj: undefined () cacache: undefined () chart.js: 3.5.0 => 3.5.0 chart.js-auto: undefined () chart.js-helpers: undefined () check-password-strength: ^2.0.3 => 2.0.3 ci-info: undefined () classnames: 2.3.1 => 2.3.1 (2.2.6) comment-json: undefined () compression: undefined () compression-webpack-plugin: ^8.0.1 => 8.0.1 conf: undefined () content-type: undefined () cookie: undefined () cross-env: ^7.0.3 => 7.0.3 crypto-browserify: ^3.12.0 => 3.12.0 css-loader: undefined () debug: undefined () devalue: undefined () dropzone: 5.9.2 => 5.9.2 email-validator: ^2.0.4 => 2.0.4 escape-string-regexp: undefined () file-loader: undefined () find-cache-dir: undefined () find-up: undefined () formik: ^2.2.9 => 2.2.9 formsy-react: ^2.2.5 => 2.2.5 fresh: undefined () fullcalendar: ^5.9.0 => 5.9.0 gzip-size: undefined () http-proxy: undefined () ignore-loader: undefined () is-animated: undefined () is-docker: undefined () is-wsl: undefined () json-parse-better-errors: ^1.0.2 => 1.0.2 json5: undefined () jsonwebtoken: undefined () loader-utils: undefined () lodash.curry: undefined () log-symbols: ^5.0.0 => 5.0.0 (2.2.0, 3.0.0) lru-cache: undefined () mini-css-extract-plugin: undefined () moment: 2.29.1 => 2.29.1 nanoid: undefined () neo-async: undefined () new-plugin-package: 1.0.0 next: ^11.0.1 => 11.0.1 next-compose-plugins: 2.2.1 => 2.2.1 next-fonts: 1.5.1 => 1.5.1 next-images: 1.8.1 => 1.8.1 next-transpile-modules: ^8.0.0 => 8.0.0 nouislider: 15.3.0 => 15.3.0 ora: undefined () password-validator: ^5.1.1 => 5.1.1 path: 0.12.7 => 0.12.7 postcss: ^8.3.6 => 8.3.6 (6.0.23, 8.2.13, 7.0.35) postcss-flexbugs-fixes: undefined () postcss-loader: undefined () postcss-preset-env: undefined () postcss-scss: undefined () pretty-checkbox: ^3.0.3 => 3.0.3 prop-types: 15.7.2 => 15.7.2 rc-checkbox: ^2.3.2 => 2.3.2 react: ^17.0.2 => 17.0.2 (17.0.1) react-anchor-link-smooth-scroll: ^1.0.12 => 1.0.12 react-bootstrap-sweetalert: 5.2.0 => 5.2.0 react-bootstrap-table-next: 4.0.3 => 4.0.3 react-bootstrap-table2-paginator: 2.1.2 => 2.1.2 react-bootstrap-table2-toolkit: 2.1.3 => 2.1.3 react-chartjs-2: 3.0.4 => 3.0.4 react-checkmark: ^1.4.0 => 1.4.0 react-copy-to-clipboard: 5.0.3 => 5.0.3 react-datetime: 3.0.4 => 3.0.4 react-dom: ^17.0.2 => 17.0.2 react-google-maps: 9.4.5 => 9.4.5 react-jvectormap: 0.0.16 => 0.0.16 react-light-accordion: ^0.1.4 => 0.1.4 react-loading-skeleton: ^2.2.0 => 2.2.0 react-notification-alert: 0.0.13 => 0.0.13 react-perfect-scrollbar: 1.5.8 => 1.5.8 react-player: ^2.9.0 => 2.9.0 react-quill: 1.3.5 => 1.3.5 react-select2-wrapper: 1.0.4-beta6 => 1.0.4-beta6 react-tagsinput: 3.19.0 => 3.19.0 react-to-print: 2.13.0 => 2.13.0 react-toastify: ^7.0.4 => 7.0.4 reactstrap: 8.9.0 => 8.9.0 recast: undefined () resolve-url-loader: undefined () rxjs: ^7.3.0 => 7.3.0 (6.6.7) rxjs/ajax: undefined () rxjs/fetch: undefined () rxjs/internal-compatibility: undefined () rxjs/operators: undefined () rxjs/testing: undefined () rxjs/webSocket: undefined () sass: ^1.37.5 => 1.37.5 sass-loader: undefined () schema-utils: undefined () semver: undefined () send: undefined () slugify: ^1.6.0 => 1.6.0 source-map: undefined () stream: ^0.0.2 => 0.0.2 string-hash: undefined () strip-ansi: undefined () styled-components: ^5.3.0 => 5.3.0 (3.4.10) styled-components/macro: undefined () styled-components/native: undefined () styled-components/no-parser: undefined () styled-components/primitives: undefined () terser: undefined () text-table: undefined () unistore: undefined () web-vitals: undefined () webpack: ^5.50.0 => 5.50.0 () webpack-bundle-analyzer: ^4.4.2 => 4.4.2 (4.3.0) webpack-sources: undefined () yarn: ^1.22.11 => 1.22.11 yup: ^0.32.9 => 0.32.9 npmGlobalPackages: @aws-amplify/cli: 5.3.0 @nestjs/cli: 7.5.6 babel-cli: 6.26.0 codesandbox: 2.2.1 create-react-app: 3.4.1 cross-env: 7.0.3 expo-cli: 3.17.16 next: 10.0.6 nodemon: 2.0.4 npm-check-updates: 11.8.3 npm: 7.20.3 npx: 10.2.2 prisma: 1.34.10 prisma1: 1.34.11 react-dom: 17.0.1 react: 17.0.1 yarn: 1.22.10 ```

Describe the bug

After I updated the Amplify packages, I just couldn't query any data using DataStore. Even though I'm working on the API Key method to enable any public access through this build, I just couldn't query any data on any pages.

Importantly, I am using NextJS

Using getServerSideProps is not the cause of the problem, though. Even if I try to call through the client-side, it complains.

The user is even authenticated, and I can get the attributes successfully using the currentAuthenticatedUser.

Here is the warning console logs.

[WARN] 00:57.531 DataStore - Realtime disabled when in a server-side environment
[WARN] 00:57.545 DataStore - User is unauthorized to query syncAdmins with auth mode API_KEY. No data could be returned.
[WARN] 00:57.545 DataStore - User is unauthorized to query syncInstructors with auth mode API_KEY. No data could be returned.
[WARN] 00:57.545 DataStore - User is unauthorized to query syncCourses with auth mode API_KEY. No data could be returned.
[WARN] 00:57.545 DataStore - User is unauthorized to query syncCompanies with auth mode API_KEY. No data could be returned.
[WARN] 00:57.545 DataStore - User is unauthorized to query syncSettings with auth mode API_KEY. No data could be returned.
[WARN] 00:57.545 DataStore - User is unauthorized to query syncCertificates with auth mode API_KEY. No data could be returned.
[WARN] 00:57.552 DataStore - User is unauthorized to query syncNewCourses with auth mode API_KEY. No data could be returned.
[WARN] 00:57.556 DataStore - User is unauthorized to query syncCourseInstructors with auth mode API_KEY. No data could be returned.

Expected behavior

The DataStore should successfully query the requested model.

Reproduction steps

Install the packages as shown above.

Code Snippet

// Put your code below this line.

Log output

``` // Put your logs below this line [WARN] 20:26.914 DataStore - User is unauthorized to query syncAdmins with auth mode API_KEY. No data could be returned. [WARN] 20:26.915 DataStore - User is unauthorized to query syncInstructors with auth mode API_KEY. No data could be returned. [WARN] 20:26.915 DataStore - User is unauthorized to query syncCourses with auth mode API_KEY. No data could be returned. [WARN] 20:26.915 DataStore - User is unauthorized to query syncCompanies with auth mode API_KEY. No data could be returned. [WARN] 20:26.915 DataStore - User is unauthorized to query syncSettings with auth mode API_KEY. No data could be returned. [WARN] 20:26.915 DataStore - User is unauthorized to query syncCertificates with auth mode API_KEY. No data could be returned. [WARN] 20:26.918 DataStore - User is unauthorized to query syncNewCourses with auth mode API_KEY. No data could be returned. [WARN] 20:26.919 DataStore - User is unauthorized to query syncCourseInstructors with auth mode API_KEY. No data could be returned. [WARN] 20:26.919 DataStore - User is unauthorized to query syncPrograms with auth mode API_KEY. No data could be returned. [WARN] 20:26.919 DataStore - User is unauthorized to query syncUsers with auth mode API_KEY. No data could be returned. [WARN] 20:26.921 DataStore - User is unauthorized to query syncProgramInstructors with auth mode API_KEY. No data could be returned. [WARN] 20:26.921 DataStore - User is unauthorized to query syncEnrolls with auth mode API_KEY. No data could be returned. [WARN] 20:26.921 DataStore - User is unauthorized to query syncTasks with auth mode API_KEY. No data could be returned. ```

aws-exports.js

const awsmobile = {
    "aws_project_region": "us-east-2",
    "aws_cognito_identity_pool_id": "us-east-2:f******",
    "aws_cognito_region": "us-east-2",
    "aws_user_pools_id": "us-east-******",
    "aws_user_pools_web_client_id": "******",
    "oauth": {
        "domain": "******-staging.auth.us-east-2.amazoncognito.com",
        "scope": [
            "phone",
            "email",
            "openid",
            "profile",
            "aws.cognito.signin.user.admin"
        ],
        "redirectSignIn": "https://localhost:3000/",
        "redirectSignOut": "https://localhost:3000/",
        "responseType": "code"
    },
    "federationTarget": "COGNITO_USER_POOLS",
    "aws_appsync_graphqlEndpoint": "https://******.appsync-api.us-east-2.amazonaws.com/graphql",
    "aws_appsync_region": "us-east-2",
    "aws_appsync_authenticationType": "API_KEY",
    "aws_appsync_apiKey": "da2-******"
};

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

No response

chris-lee-code commented 3 years ago

@chrisbonifacio I want to know if there are particular, new ways to query DataStore with API_Key. Updating the package caused this problem. For now, I just want to enable the public access of anyone.

chrisbonifacio commented 3 years ago

Hi @supersonix77 👋 As far as I know, DataStore will try to use the default authentication as set in the Amplify configuration file (aws-exports). Could you provide the code for how you're configuring Amplify and attempting make the query from both the client and the server?

chris-lee-code commented 3 years ago

Hi @chrisbonifacio. For the configuration details, I attached them above. About how I configured the app, it didn't change at all. I just put the Amplify.configure({ ...awsmobile, ssr: true }); in _app.js. Just in case to see if the Amplify.configure() doesn't work, I even tried to put it on the particular page I'm requesting the query.

But it still complains for all the models with the error below.

User is unauthorized to query syncTasks with auth mode API_KEY. No data could be returned.

The Tasks for syncTasks is just the name of the model. Will it help for me to change it to other auth modes like Cognito User Pool?

chris-lee-code commented 3 years ago

@chrisbonifacio First of all, just to test out my curiosity, changing the auth mode from API Key to AMAZON_COGNITO_USER_POOLS made the same problems.

DataStore - User is unauthorized to query syncAdmins with auth mode AMAZON_COGNITO_USER_POOLS. No data could be returned.

chris-lee-code commented 3 years ago

This is how the models are designed.

enum AdminRole {
  SUPERADMIN
  COMPANYADMIN
  MANAGER
}

type Admin @model @auth(rules: [{allow: public}]) @key(name: "byCompany", fields: ["companyID"]) {
  id: ID!
  userID: String
  role: AdminRole
  companyID: ID
}

type NewCourse @model @auth(rules: [{allow: public}]) @key(name: "byProgram", fields: ["programID"]) {
  id: ID!
  title: String
  programID: ID
  description: String
  skillTags: [String]
  majorSkill: String
  modelAnswerLink: String
  videoLink: String
  bannerImgLink: String
  Instructor: Instructor @connection
  instructorID: String
}

type Course @model @key(name: "byProgram", fields: ["programID"]) @auth(rules: [{allow: public}]) {
  id: ID!
  title: String
  courseNo: Int
  slugTitle: String
  programID: ID
  Instructors: [CourseInstructor] @connection(keyName: "byCourse", fields: ["id"])
  description: String
  skillTags: [String]
  majorSkill: String
  modelAnswer: String
  videoCode: String
  bannerImg: String
}

type Task @model @auth(rules: [{allow: public}]) {
  id: ID!
  isSubmitted: Boolean
  fileLink: String
  Course: Course @connection
  User: User @connection
}

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

type Instructor @model @key(name: "byCompany", fields: ["companyID"]) @auth(rules: [{allow: public}]) {
  id: ID!
  firstName: String
  lastName: String
  jobTitle: String
  companyID: ID
  profileImg: String
  profileBanner: String
  slugTitle: String
  programs: [ProgramInstructor] @connection(keyName: "byInstructor", fields: ["id"])
  courses: [CourseInstructor] @connection(keyName: "byInstructor", fields: ["id"])
  description: String
  linkedin: String
}

type Certificate @model @auth(rules: [{allow: public}]) @key(name: "byUser", fields: ["userID"]) {
  id: ID!
  referenceID: String
  userID: ID
  programID: String
}

type Program @model @key(name: "byCompany", fields: ["companyID"]) @auth(rules: [{allow: public}]) {
  id: ID!
  title: String
  slugTitle: String
  category: String
  programLogo: String
  programBanner: String
  Courses: [Course] @connection(keyName: "byProgram", fields: ["id"])
  companyID: ID
  Company: Company @connection
  description: String
  introVideoCode: String
  finalVideoCode: String
  ProgramInstructors: [ProgramInstructor] @connection(keyName: "byProgram", fields: ["id"])
  NewCourses: [NewCourse] @connection(keyName: "byProgram", fields: ["id"])
}

type Company @model @auth(rules: [{allow: public}]) {
  id: ID!
  title: String
  slugTitle: String
  logoImg: String
  bannerImg: String
  Programs: [Program] @connection(keyName: "byCompany", fields: ["id"])
  website: String
  description: String
  category: String
  logoWhite: String
  Instructors: [Instructor] @connection(keyName: "byCompany", fields: ["id"])
  Admins: [Admin] @connection(keyName: "byCompany", fields: ["id"])
}

type Enroll @model @key(name: "byUser", fields: ["userID"]) @auth(rules: [{allow: public}]) {
  id: ID!
  User: User @connection
  userID: ID
  programID: String
}

type User @model @auth(rules: [{allow: public}]) {
  id: ID!
  given_name: String
  family_name: String
  username: AWSEmail
  Enrolls: [Enroll] @connection(keyName: "byUser", fields: ["id"])
  Settings: Settings @connection
  Certificates: [Certificate] @connection(keyName: "byUser", fields: ["id"])
}

type ProgramInstructor @model(queries: null) @key(name: "byProgram", fields: ["programID", "instructorID"]) @key(name: "byInstructor", fields: ["instructorID", "programID"]) @auth(rules: [{allow: public}, {allow: public}]) {
  id: ID!
  programID: ID!
  instructorID: ID!
  program: Program! @connection(fields: ["programID"])
  instructor: Instructor! @connection(fields: ["instructorID"])
}

type CourseInstructor @model(queries: null) @key(name: "byCourse", fields: ["courseID", "instructorID"]) @key(name: "byInstructor", fields: ["instructorID", "courseID"]) @auth(rules: [{allow: public}, {allow: public}]) {
  id: ID!
  courseID: ID!
  instructorID: ID!
  course: Course! @connection(fields: ["courseID"])
  instructor: Instructor! @connection(fields: ["instructorID"])
}
chris-lee-code commented 3 years ago

@chrisbonifacio Funny thing is that even if I only query 1~2 Models on a page, the error always includes the sync of all the models that exist.

Below is the example of how I try to get on the server-size using the getServerSideProps

import React, { useEffect, useState } from "react";
import AuthLayout from "layouts/Auth.js";
import Button from "reactstrap/lib/Button";
import { DataStore } from "@aws-amplify/datastore";
import { Hub, withSSRContext } from "aws-amplify";
import { Program, User } from "../../src/models";

export async function getServerSideProps(context) {
  const { Auth, DataStore } = withSSRContext(context);
  let user = null;
  let isAuthenticated = false;
  let dataStoreUser = null;

  try {
    const { attributes } = await Auth.currentAuthenticatedUser();
    if (attributes) {
      user = JSON.parse(JSON.stringify(attributes));
      isAuthenticated = true;
    } else {
      console.log("User is not logged in.");
      isAuthenticated = false;
      user = null;
    }
  } catch (error) {
    console.log("Error getting user: ", error);
  }
  if (user !== null && user !== undefined) {
    try {
      const dataStoreUserQuery = await DataStore.query(User, (userData) =>
        userData.username("eq", user.email)
      );
      console.log("DataStore user: ", dataStoreUserQuery[0]);
      dataStoreUser = JSON.parse(JSON.stringify(dataStoreUserQuery[0]));
    } catch (error) {
      console.log(
        "Error getting the DataStore User from getServerSideProps: ",
        error
      );
    }
  }
  return {
    props: {
      user: user,
      isAuthenticated: isAuthenticated,
      dataStoreUser: dataStoreUser,
    },
  };
}

For the code above, the getServerSideProps at least successfully get the Auth.currentAuthenticatedUser();.

On the client-side, I do as follow.

const getUser = async () => {
    try {
      console.log(DataStore);
      const dataStoreUser = await DataStore.query(User);
      console.log("User: ", dataStoreUser);
      setDataStoreUser(dataStoreUser);
      const anyProgram = await DataStore.query(Program);
      console.log("Program: ", anyProgram);
    } catch (error) {
      console.log("error getting datastoreuser: ", error);
    }
  };
  function handleClick(event) {
    event.preventDefault();
    console.log("Clicked");
    getUser();
  }

return (
    <>
      <div>
        <div style={{ minHeight: "100px" }}></div>
        <Button className="mt-5" onClick={handleClick}>
          Get User
        </Button>
      </div>
    </>
  );

On the client-side, when I trigger the getUser() by the onClick method, the console.log() gets query results of none.

User:  []
Program:  []

PLEASE HELP!!

chris-lee-code commented 3 years ago

Why would a page with only 1~2 Models to query even start the whole sync process with all the models?

[WARN] 32:09.530 DataStore - Realtime disabled when in a server-side environment
[WARN] 32:09.540 DataStore - User is unauthorized to query syncAdmins with auth mode API_KEY. No data could be returned.
[WARN] 32:09.540 DataStore - User is unauthorized to query syncInstructors with auth mode API_KEY. No data could be returned.
[WARN] 32:09.540 DataStore - User is unauthorized to query syncCourses with auth mode API_KEY. No data could be returned.
[WARN] 32:09.540 DataStore - User is unauthorized to query syncCompanies with auth mode API_KEY. No data could be returned.
[WARN] 32:09.540 DataStore - User is unauthorized to query syncSettings with auth mode API_KEY. No data could be returned.
[WARN] 32:09.540 DataStore - User is unauthorized to query syncCertificates with auth mode API_KEY. No data could be returned.
[WARN] 32:09.543 DataStore - User is unauthorized to query syncNewCourses with auth mode API_KEY. No data could be returned.
[WARN] 32:09.543 DataStore - User is unauthorized to query syncCourseInstructors with auth mode API_KEY. No data could be returned.
[WARN] 32:09.543 DataStore - User is unauthorized to query syncPrograms with auth mode API_KEY. No data could be returned.
[WARN] 32:09.543 DataStore - User is unauthorized to query syncUsers with auth mode API_KEY. No data could be returned.
[WARN] 32:09.544 DataStore - User is unauthorized to query syncProgramInstructors with auth mode API_KEY. No data could be returned.
[WARN] 32:09.544 DataStore - User is unauthorized to query syncEnrolls with auth mode API_KEY. No data could be returned.
[WARN] 32:09.544 DataStore - User is unauthorized to query syncTasks with auth mode API_KEY. No data could be returned.
chris-lee-code commented 3 years ago

@chrisbonifacio I found out there is a consistent warning from the console. DataStore - Data won't be synchronized. No GraphQL endpoint configured. Did you forget Amplify.configure(awsconfig)?

But I already put the config like this. Amplify.configure({ ...awsmobile, ssr: true }); in _app.js

Is there anything to do with this configuration?

chrisbonifacio commented 3 years ago

@supersonix77 hmm, okay. Yeah, your code seems correct from what I can tell. Are you getting that error message on both the client and the server?

Could you try using API.graphql on the server side and see if that works? I've seen issues where DataStore is not being authorized properly on the server side while API might still work.

chris-lee-code commented 3 years ago

@chrisbonifacio Awesome! I just found out the API GraphQL works perfectly. However, why does this even happen? Will I have to change all the DataStore queries to API queries?? It's going to be a big construction🥲

chris-lee-code commented 3 years ago

@chrisbonifacio There must be reasons why you guys build DataStore and API.graphql (even API REST) all separately. What are the potential disadvantages with migrating from DataStore to API.graphql?? I don't want to risk the whole project out of this unusual error that might be addressed later in the future.

One potential issue that I can think of is that the DataStore just right now has a problem with detecting the Amplify.configure() in the _app.js. But if API is able to get the data from the console, that means the configuration is properly propagated when the API.graphql queries data.

스크린샷 2021-08-14 오후 1 47 10

The authProviders in the config are undefined. Meanwhile, the API.graphql works on both server-side and client-side.

I think now should be good timing for you to make a proper error report regarding this matter. This is surely an error with AWS Amplify -- error when the DataStore accesses the configuration that works in API

chrisbonifacio commented 3 years ago

The main difference functionally between using DataStore and API is the offline capability. However, if that is not important to you or your users then API should be able to get the job done. As far as the DataStore issues with SSR, part of the difficulty in getting it and other Amplify libraries to work the same way they do on the client is that every server side request has to reinitialize Amplify on the server and each library uses Credentials in a different way/at different levels that withSSRContext needs to account for. So, it will be some time before everything works exactly the way it does on the client but that is the goal.

Apologies for the inconveniences in the server side but if you want users to use DataStore on the client and API on the server, I believe that fits both library's use cases better than using DataStore in both scenarios. Let me know if this would allow you to continue your work in the meantime while we look into the issue.

That being said, I am putting together a report of the issues you and other customers are experiencing with DataStore in an SSR context and will bring it to the team's attention. Thank you for helping us find bugs and making our libraries better 🙏

chris-lee-code commented 3 years ago

@chrisbonifacio Thank you for your prompt and kind response! It really clarified the main purposes of API and DataStore.

And I think that's a great approach to use API on the server-side and DataStore on the client-side. However, the main issue is that since the configuration doesn't work for DataStore, I just cannot use DataStore at all -- even on the client-side.

Even putting the Amplify.configure({...awsmobile, ssr:true}) on the page doesn't help. Is there any way to propagate the configuration again on the client-side?

useEffect(()=>{Amplify.configure({...awsmobile, ssr:true})},[])
//Call Amplify.configure only on the client-side when the pre-build is completed.

I'm just worried about unexpected behaviors due to multiple configuration calls initiated by several pages and functions.

Using API with custom queries seems a lot harder compared to DataStore where I can just query with whatever attributes the model has. I think API is straightforward only if we have the id ready on the page so that we can quickly query with the particular id. Otherwise, it's a lot more difficult. Anyway, thanks for reporting the issues!

chris-lee-code commented 3 years ago

@chrisbonifacio Is this a valid and the best way to query API using fields other than id? https://stackoverflow.com/questions/67430279/amplify-graphql-get-item-from-other-field-than-id

chrisbonifacio commented 3 years ago

@supersonix77 Yes, you would have to use the @key directive to add secondary indexes to your models.

https://docs.amplify.aws/cli/graphql-transformer/key/#how-to-use-key

Also, no problem! I'm currently still trying to reproduce the issue you're having with DataStore on the client because I believe that one should still work. It's strange to me that it's not recognizing the graphql endpoint, I haven't seen that error before so I'm not exactly sure how to fix it just yet as I've been unsuccessful in reproducing it on my end.

If you wouldn't mind adding me to your repo temporarily so that I may pull down your app and try it with your exact code. I should be able to reproduce it consistently I hope.

chris-lee-code commented 3 years ago

@chrisbonifacio Thank you for letting me know!

Alright. So I just invited you to my repo as a collaborator. Please take a look at the "beta" branch.

  1. npm run dev
  2. Surf to localhost:3000/program. The code can be found in pages/program/index.js
  3. Then in the getServerSideProps, you will be able to find the code below that I intentionally split into two parts just to let you know how they work differently.
    console.log("Getting programs...");
    const dataStoreProgramsQuery = await DataStore.query(Program);
    console.log(
      "Results from getting DataStore programs: ",
      dataStoreProgramsQuery
    );
    const programsQuery = await API.graphql({ query: queries.listPrograms });
    console.log("API Program: ", programsQuery.data.listPrograms.items);

    Please let me know what other information you would need to address this issue!

chrisbonifacio commented 3 years ago

@supersonix77 I managed to get the DataStore queries to work on both the client and server side. I noticed that you were importing Amplify modules by their scoped packages. I would not recommend this if you're using aws-amplify with SSR. So, I removed those and imported the modules from aws-amplify instead and it started to work.

You also happen to have two instances where Amplify.configure is being called. I think you only need the one instance in _app.js.

Pushing up the branch as cbonifacio/fix-datastore-issues

Client

Screen Shot 2021-08-17 at 2 10 38 PM

Server

Screen Shot 2021-08-17 at 2 10 53 PM
chris-lee-code commented 3 years ago

@chrisbonifacio Thanks! I think this is literally what the "WOW customer experience" means.

However, unfortunately, that didn't fix the error on my side. Looking at your console having a different example program, I believe you created your own Amplify backend so that you can make it on your own. The only possibility now I can think of is there is something wrong with the Amplify backend (since you used the identical code).

스크린샷 2021-08-18 오전 8 49 23

Are there any ways I can invite you to my real Amplify project so that you can check if there is anything wrong with the configuration??

chrisbonifacio commented 3 years ago

Ahh okay, I see what you mean. There must be some differences between our auth configurations for either API or Auth. Do you get this error even before logging in? Or only after logging in?

Also, for me to use your backend you would have to share your aws-exports file with me (you can do so by emailing me at Christopher.bonifacio@gmail.com). It would point my client towards your Auth and API resources.

chris-lee-code commented 3 years ago

@chrisbonifacio It happens both before and after logging in. Since I configured the auth mode as API Key, not Cognito User Pool, I don't think signing in really makes changes.

I just sent you the aws-exports file to the email. Please take a look!

chrisbonifacio commented 3 years ago

@supersonix77 Thank you! I've been taking a look at the app with your aws-exports and unfortunately I'm still not able to reproduce the DataStore - User is unauthorized to query syncAdmins with auth mode API_KEY. No data could be returned. error. It's really strange, I'm not sure what the issue is. My best guess is maybe it's particular to the user. Maybe try creating a new user and see if the issue persists?

I tried both logged out (API_KEY) and logged in (Cognito User Pools)

Logged Out

Screen Shot 2021-08-18 at 10 57 49 AM

Logged In

Screen Shot 2021-08-18 at 10 57 31 AM

You can see I removed the API call completely, so I'm only using DataStore.

Screen Shot 2021-08-18 at 11 43 09 AM

🤷‍♂️

chrisbonifacio commented 3 years ago

Tried on the client side as well, still worked 😕

Logged Out (Client)

Screen Shot 2021-08-18 at 11 16 39 AM

Logged In (Client)

Screen Shot 2021-08-18 at 11 20 13 AM
chrisbonifacio commented 3 years ago

@supersonix77 I was finally able to reproduce the issue. I realized that I was one version of aws-amplify ahead of you on my local branch so I downgraded to 4.2.2 and got the error. However, when I upgraded back to 4.2.3 I was still getting it. I had to delete node_modules and the package-lock.json file and reinstall all the dependencies (stuck with aws-amplify@4.2.3) for the error to go away again.

There must have been incompatible package versions or the dependency tree just got messed up somehow. Also, I noticed that you have the @aws-amplify/cli as a dependency in your project. That should either be a global or dev dependency. But yeah, try deleting node_modules and the package-lock.json file, then maybe use yarn to install your dependencies. I ran into issues trying to install all of them with npm. Got this error in particular.

Screen Shot 2021-08-18 at 1 00 11 PM
chris-lee-code commented 3 years ago

@chrisbonifacio Thank you so much for fixing the errors! You saved my life twice so far haha.

I still don't get why using npm will cause the issue, while yarn will not. At least now I understand the risk of fixing the conflicts with either npm install --force or npm install --legacy-peer-deps. So I assume even the aws-amplify package has some conflicts with its peer dependencies.

I wish this bug report helped both of us fix issues like this from now on for us and other users as well.

Thank you so much for helping out!😆

"WOW customer experience"😏 👍

chrisbonifacio commented 3 years ago

Anytime! Thanks for being so patient and accommodating while I tried to reproduce the issue. Definitely helped me find a fix and get you back to a working state quicker 😃

Btw, I spoke to one of the team members about using DataStore on the server side and they said that API would be more performant there because DataStore performs a sync when it starts and tries to get all the data from AppSync. This is not ideal as it will do this on every request as withSSRcontext needs to reinitialize Amplify on each request.

So, I would definitely recommend leveraging API inside of getServerSideProps if it's not too much trouble to refactor. Otherwise, just something to consider if you need to optimize in the future.

Again, the main benefits of using DataStore are the offline capabilities it provides on the client which you can read more about here:

https://aws.amazon.com/blogs/aws/amplify-datastore-simplify-development-of-offline-apps-with-graphql/

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.