Amplify-js: Amplify DataStore in React Native

Created on 6 Dec 2019  Âˇ  64Comments  Âˇ  Source: aws-amplify/amplify-js

I'm trying to use the new Amplify DataStore in React Native by adapting the instructions at https://aws.amazon.com/blogs/aws/amplify-datastore-simplify-development-of-offline-apps-with-graphql/ but I get a "Node is not supported" error.

Looking at this code: https://github.com/aws-amplify/amplify-js/blob/8e515adf3858af57029d5e2d76512ad14db3d62b/packages/datastore/src/storage/storage.ts#L24 it seems like IndexedDB is required, and I think it might not work in React Native.

Is there some special configuration or dependencies needed to make Amplify DataStore work in React Native?

DataStore React Native feature-request

Most helpful comment

Is there any update on this? A timeline, or a workaround would be great. Especially since it was announced as being compatible with React Native: https://aws.amazon.com/about-aws/whats-new/2019/12/introducing-amplify-datastore/

All 64 comments

https://twitter.com/undef_obj/status/1203072936237682689

React Naive bindings aren't published yet, need to get all the iOS and Android storage adapters fully published due to changes in the React Naive bridging system. Now that it's out we can get these bits published in the coming weeks then docs will get updated.

Great I will be waiting too.

Is there any update on this? A timeline, or a workaround would be great. Especially since it was announced as being compatible with React Native: https://aws.amazon.com/about-aws/whats-new/2019/12/introducing-amplify-datastore/

The advice of coming weeks was 27 days ago so hopefully not far away.

Any updates on this yet and when shall we be expecting?

Curious about expo compatibility than

From the twitter link in the issue immediately above, it looks like there is finally some movement:

We got a working prototype this past week and are looking to see if we can get it release ready in the next week or so.

Update everyone, we believe we have a path forward for a release soon. Will reply when we have an ETA

is there any update on the availability of these components? We have projects depending on it and it would really help to know if we should wait for this or use google firebase.

Again from the twitter link, it looks like work is nearing completion bar for a few issues, and will be communicated here shortly.

Very excited for this, and thanks to everyone working on it :)

Amplify DataStore React Native Pre-Release

Hi All,

Today we published a pre-release of Amplify DataStore on React Native with a storage adapter that uses AsyncStorage underneath.
Please follow the instructions below to set up and test your App.

Setup the App

1) Create the app:

npx react-native init DatastoreApp
cd DataStoreApp

2) Install amplify related dependencies:

npm install -E @aws-amplify/core@rn-datastore @aws-amplify/datastore@rn-datastore 

3) Install and Link NetInfo:
For step 3, there are different instructions for Expo apps vs React Native CLI based apps. Follow the steps that are relevant for your setup:

  • For Expo Managed Apps:
    Install NetInfo with expo
expo install @react-native-community/netinfo

Thats all for Expo managed apps. Move directly to step 4)

  • For Apps created with React Native CLI:
    Install NetInfo through npm
npm install @react-native-community/netinfo

If using React Native > 0.60, run the following for iOS.

cd ios && pod install && cd ..

If you are using React Native <0.60 and need to link manually, refer to the react-native-community/netinfo getting started guide

4) Add Amplify DataStore to the app:
From the root directory of your app, run the following:

npx amplify-app@latest

5) Update the the schema:
After this completes, you can update the default GraphQL schema by modifying the following file:
amplify/backend/api/amplifyDatasource/schema.graphql

For this example we are going to use the following schema:

enum PostStatus {
  ACTIVE
  INACTIVE
}

type Post @model {
  id: ID!
  title: String!
  comments: [Comment] @connection(name: "PostComments")
  rating: Int!
  status: PostStatus!
}

type Comment @model {
  id: ID!
  content: String
  post: Post @connection(name: "PostComments")
}

6) Run codegen for the schema:
After saving the file, run the following command to generate your models:

 npm run amplify-modelgen

7) Create your API and cloud resources:

npm run amplify-push

8) Modify your App.js file:
In order to follow along with this example, replace your existing App.js file with this code.

9) Run the app
Run on iOS: npx react-native run-ios
_or_
Run on Android: npx react-native run-android

Test some DataStore use-cases in the App

Navigate to the AppSync console for your API
Run the following command from the root directory of your App:

amplify console api

Select GraphQL and press enter:

❯ GraphQL 
  REST 

A new tab will open in your browser that takes you to your AppSync API

Add some GraphQL queries to test in the console
Open the Queries tab of the AppSync Console. It contains an in-browser tool for writing, validating, and testing GraphQL queries. Add the following snippets to the editor on the left:

query getComments{
  syncComments {
    items {
      _deleted
      id
      content
      post {
        id
      }
    }
  }
}

query getPosts {
  syncPosts {
    items {
      id
      _deleted
      title
    }
  }
}

mutation createPost { 
  createPost(input: {
    title: "Post from backend",
    rating: 5,
    status: ACTIVE
  }) {
    id
    title
    rating
    status
    _version
    _deleted
    _lastChangedAt
  }

}

To run one of the above queries/mutations press the play button, and select the query you want to run.

Test Save

In the simulator, click ‘Create One Post’:

1) A post will show up on the UI
2) In the AppSync console click ‘getPosts’ to verify the Post is created in the backend.

Test Save for the for the one-many case

In the simulator click ‘Create Post & Comments’ (Should create one post with 2 comments)

1) Only the post will show up on the UI
(Comments are not rendered on the UI but if you are running the debugger, then you will see all comments in console.log statements)
2) In AppSync console click:

  • ‘getPosts’ to confirm that the Post is created in the backend.
  • ‘getComments’ to confirm that the comments are created in the backend.

Test Subscriptions

In the AppSync console click ‘createPost’:

1) The post should show up on the simulator UI

Test Queries
Queries are run as soon as the App starts, as well as whenever there is an update from a subscription. If you see data updated on the UI, the queries are running correctly.

You can test further by modifying the conditions in the code to filter results such as by rating, etc.

Test Delete

In the simulator click ‘DeletePosts’:

1) All the posts are deleted and disappear from the UI
2) In AppSync console click:

  • ‘getPosts’ to confirm that all the Posts returned have "_deleted": true
  • ‘getComments’ to confirm that all the comments returned have "_deleted": true

_Note:_ If you would like to see the data in AsyncStorage for debugging purposes, click on ‘Get Store’ in the Simulator and make sure you have the debugger open.

Some Known Issues

Since this is a pre-release, there are some known issues below that we will be working on before the final release.

  • Currently the reachability aspect (detecting online/offline status) does not work very reliably when the app is in the background or if we switch off the internet and come back online. Offline data will be persisted but the subscriptions do not work immediately. Sometimes it takes a while for the app to come online, or you need to kill the app. After that the data is synced to the backend.
    Also note, NetInfo does not work correctly on iOS Simulator: https://github.com/react-native-community/react-native-netinfo/issues/7

  • We get some warnings in android regarding setTimeout which is probably part of the pubsub piece.

  • Issues with Buffer: https://github.com/facebook/react-native/issues/14796
    We can try adding buffer as a dependency/peer-dependency. Or currently users need to add the following line in their Apps:

global.Buffer = global.Buffer || require('buffer').Buffer

Thank you

Your testing will help us get the final build out sooner so please let us know your feedback. Thank you.

Great news!

One quick question: Do the instructions work with a non-ejected Expo app, or is that currently not supported? If not, could you confirm if that use case is intended to be supported in the final release?

@danrivett While we have not yet tested on Expo apps, in theory it should work since all the dependencies like AsyncStorage and NetInfo are a part of Expo and wont require you to eject.

Do give it a try and let us know if you face any issues. I will be trying it out as well this week.

@danrivett While we have not yet tested on Expo apps, in theory it should work since all the dependencies like AsyncStorage and NetInfo are a part of Expo and wont require you to eject.

Do give it a try and let us know if you face any issues. I will be trying it out as well this week.

I guess you use asyncStorage from community?
So we have to use asyncStorage from „react-native“ with Expo.

@danrivett While we have not yet tested on Expo apps, in theory it should work since all the dependencies like AsyncStorage and NetInfo are a part of Expo and wont require you to eject.

Do give it a try and let us know if you face any issues. I will be trying it out as well this week.

I try in my app in expo but i have the issue [Unhandled promise rejection: Error: Node is not supported]

Thanks all. iOS seems to work fine (except for subscriptions which per above seems to be expected)
Android does not work - I get a runtime error Cannot use t"__Schema" from another module or realm
I have tried recreating it a couple of times but can't get around this error, eg:

    "dependencies": {
        "@aws-amplify/core": "^2.2.5-rn-datastore.3",
        "@aws-amplify/datastore": "^1.0.7-rn-datastore.3",
        "@react-native-community/netinfo": "^5.5.0",
        "graphql": "^14.6.0",  <-- Install this explicitly, using 14.0.0 and others
        "react": "16.9.0",
        "react-native": "0.61.5"
    },
    "resolutions": {
        "@aws-amplify/**/graphql": "^14.6.0" <-- No difference to error
    },

I have a project using the web and react-native with the shared codebase. I tried to upgrade everything to rn-datastore.3 version and play with it. However, the web is working fine and is syncing data with the AppSync, but the iOS side can't retrieve objects. I constantly get an empty array [].
Is it supposed to be working with "authenticationType": "AMAZON_COGNITO_USER_POOLS"?

@Ashish-Nanda
What about the fact that Async Storage has a limit of 6MB.
https://github.com/facebook/react-native/issues/7869
Is it planned to be replaced, and if so, for what?

@Ashish-Nanda
What about the fact that Async Storage has a limit of 6MB.
facebook/react-native#7869
Is it planned to be replaced, and if so, for what?

@gHashTag

The size limitation for AsyncStorage is only on Android that can also be address with some configuration: https://github.com/react-native-community/async-storage/blob/LEGACY/docs/advanced/IncreaseDbSize.md

Moreover, AFAIK it's being worked on AsyncStorage v2 that would allow to create custom solutions how AsyncStorage persists the data. I guess one of the option would be writing to files (as iOS does?) or something else that would be more flexible.

I try to save data and got next error

      const post =  await DataStore.save(
          new Post({
            title: `My Test post`,
            rating: 10,
            status: PostStatus.ACTIVE
          })
      );

[InvalidStateError: Failed to execute 'objectStore' on 'IDBTransaction': The transaction has finished.]
Source https://github.com/dimonchik-com/TestDataStore

@dimonchik-com @CarlitosBeto Its seems like your app is not picking up the React Native specific files and instead using web specific code. I will try out the test app you linked to as well as an expo app and report back. In the meantime could you try to run the app again after deleting node modules, and resetting the packager cache?

@dimonchik-com @CarlitosBeto Its seems like your app is not picking up the React Native specific files and instead using web specific code. I will try out the test app you linked to as well as an expo app and report back. In the meantime could you try to run the app again after deleting node modules, and resetting the packager cache?

I try to remove node_modules how you said and then run
npm install
yarn
and then got next error
Error: Node is not supported

@Ashish-Nanda please can you share any steps to configure correctly the project. I try removed the files and continue with the same error Node is not supported

@Ashish-Nanda please can you share any steps to configure correctly the project. I try removed the files and continue with the same error Node is not supported

@CarlitosBeto "Node not supported" sounds like you might be using the adapter in @latest which doesn't yet support React Native rather than @rn-datastore npm tag. It also could be that the React Native bundler still has a cached copy so you might have to try clearing your dependency tree or a new project. This is what should be used:

npm install @aws-amplify/core@rn-datastore @aws-amplify/datastore@rn-datastore

@Ashish-Nanda please can you share any steps to configure correctly the project. I try removed the files and continue with the same error Node is not supported

Hi @CarlitosBeto the steps to install and configure are detailed in this comment above.

Please check that you have installed dependencies with the @rn-datastore tag as @undefobj commented above.
Your package.json should have something like:

"dependencies": {
        "@aws-amplify/core": "^2.2.5-rn-datastore.3",
        "@aws-amplify/datastore": "^1.0.7-rn-datastore.3",
        ...
    },

If the above is true but you are still facing the issue then try the following:

  1. rm -rf node_modules
  2. rm -rf /tmp/metro-*
  3. yarn start --reset-cache

If the issue still persists then let us know. It would be super helpful if you can share a link to your project so we can debug further.

@dimonchik-com I think I resolved the issue you were facing.
I checked out your project code locally, and faced the same issues initially. After looking in the node_modules I found that the wrong version of @aws-amplify/datastore was being installed.

I think the issue is with your yarn.lock file. You can see from these lines that the version that is getting installed is from the @unstable tag rather than @rn-datastore.

@CarlitosBeto you might be having a similar issue as well, so please follow the steps below to see if it also resolves your issue.

Follow these steps to fix the issue:

  • Delete your lock files:
rm yarn.lock package-lock.json
  • Modify your package.json to always explicitly install from the rn-datastore tag:
"dependencies": {
        "@aws-amplify/core": "rn-datastore",
        "@aws-amplify/datastore": "rn-datastore",
        "@react-native-community/netinfo": "^5.5.0",
        "react": "16.9.0",
        "react-native": "0.61.5"
    },
  • Delete your node_modules:
rm -rf node_modules/
  • Delete Metro Packager cache:
 rm -rf /tmp/metro-*
  • Start your packager with the reset cache option:
    From the root directory of your app, run:
yarn start --reset-cache
  • Open your app in the simulator and reload it
    eg. Press Cmd + R for iOS Simulator

This should hopefully make sure you install the correct version of the datastore dependency always.

To be extra sure you have the correct dependency installed, once your node_modules are installed you can also check this by:
1) Going to <ProjectRootDirectory>/node_modules/@aws-amplify/datastore/package.json
and if you open the file, you should see something like:

"version": "1.0.7-rn-datastore.3+0d78e166"

2) Also you can go to the folder:
<ProjectRootDirectory>/node_modules/@aws-amplify/datastore/lib/storage/adapter .
And check you have these files:

AsyncStorageDatabase.js
asyncstorage.js

Hopefully this resolves your issue. I was able to save and query posts based using your App. Do let me know if this worked for you.

Managed to get this working with my react-native app but for some reason there is no sync happening with the actual backend.. If I save the data locally, it will appear in the queries, but won't fetch pre-existing data (I added datastore to existing project).. Wondering if it's related to https://github.com/react-native-community/react-native-netinfo/issues/7 ? Is there a way to manually trigger a sync for the datastore?

@cipriancaba same issue for me, can't get to sync with actual backend. Tried on the simulator and on an actual device, and the result is the same - it saves and persists locally but does not sync with AppSync backend.

@Ashish-Nanda first many thanks, i try with your instructions but i have 2 issues:
1) I install the correct packages and result the following error:
AuthError -
Error: Amplify has not been configured correctly.
This error is typically caused by one of the following scenarios:

        1. Make sure you're passing the awsconfig object to Amplify.configure() in your app's entry point
            See https://aws-amplify.github.io/docs/js/authentication#configure-your-app for more information

        2. There might be multiple conflicting versions of aws-amplify or amplify packages in your node_modules.
            Try deleting your node_modules folder and reinstalling the dependencies with `yarn install`

these are my packages
"@aws-amplify/core": "^1.0.7-rn-datastore.3",
"@aws-amplify/datastore": "^1.0.7-rn-datastore.3",
"@react-native-community/netinfo": "^5.5.0",
"aws-amplify-react-native": "^3.2.3-rn-datastore.3",

I follow the instructions for fix the error but It is not working, this error ocurred when install "@aws-amplify/core": "^1.0.7-rn-datastore.3" for fix the error i change the package for "aws-amplify": "^2.2.5-rn-datastore.3", but return the error node is not supported

2) I try with other package for example:
"@aws-amplify/datastore": "^1.0.7-rn-datastore.3",
"@react-native-community/netinfo": "^5.5.0",
"aws-amplify": "^2.2.5-rn-datastore.3",
"aws-amplify-react-native": "^3.2.3-rn-datastore.3",
in this case return the error Node is not supported, but the auth work fine
I supuose the dependecies is wrong but I can't fix them.

Managed to get this working with my react-native app but for some reason there is no sync happening with the actual backend.. If I save the data locally, it will appear in the queries, but won't fetch pre-existing data (I added datastore to existing project).. Wondering if it's related to react-native-community/react-native-netinfo#7 ? Is there a way to manually trigger a sync for the datastore?

@cipriancaba @edvinasbartkus If you are using a pre-existing Amplify project you'll need to ensure that you've created a sync-enabled Data Source ("Enable Data Source versioning" is selected in the AppSync console) and the resolver is configured with conflict resolution as well as a "sync" operation. This can be done if you modify your API using the CLI when it asks the "Advanced Configuration" option, however we recommend for now it's better to test by creating a new API via the npx amplify-app@latest flow outlined above as it configures all these things for you.

We are looking at improving the CLI flow for adding DataStore to existing APIs in the future, but right now we want to first ensure that we have solid testing and functionality of the React Native adapter with a known flow.

@edvinasbartkus reading your comment it seems you have a webapp already setup and working with Amplify Datastore and not just the API category, correct?

Could you elaborate more/provide some repro steps regarding your setup and how you are sharing the backends between the platforms so I can try to replicate and test it? I assume your exports file has the same resource ids, etc.

Also we discovered a bug right now with Datastore that we are fixing, where sync doesnt always work unless you have issued a query initially. This is not specific to React Native, and we are putting in a fix soon. In the meantime, could you add a call to query in your componentDidMount() method to ensure it happens before any save operations? Let me know if that changes anything.

@Ashish-Nanda that is correct, I am reusing the codebase for the webapp and react native project, it has AppSync, DataStore, and Auth in place. Web version works well, it is calling DataStore methods to query and save. Mobile uses the same code, it persists locally but does not sync.

I will try to put querying first (DataStore.query, right?), just to check but I am pretty sure I am already doing it - querying first, saving later on click.

I have this set up in a pretty minimal project. Later today, if I don't get it working, I could pack it and share it with you to reproduce.

@Ashish-Nanda that is correct, I am reusing the codebase for the webapp and react native project, it has AppSync, DataStore, and Auth in place. Web version works well, it is calling DataStore methods to query and save. Mobile uses the same code, it persists locally but does not sync.

I will try to put querying first (DataStore.query, right?), just to check but I am pretty sure I am already doing it - querying first, saving later on click.

I have this set up in a pretty minimal project. Later today, if I don't get it working, I could pack it and share it with you to reproduce.

Got it! Yes, do execute DataStore.query(...) first, similar to how its done here:

It would be great if you could share the project on Github. It would help us test and debug further, so do drop a link to the repo if the above suggestion does not work.

Also let us know any additional details regarding the configuration of your app. Are you using Cognito User Pools or API Key for Auth?
I saw in this comment you mentioned "authenticationType": "AMAZON_COGNITO_USER_POOLS" but wasnt sure if that was part of your configuration or just a general question.

@Ashish-Nanda yes, I am using "authenticationType": "AMAZON_COGNITO_USER_POOLS"

Good news, I have managed to recreate a sample project sharing web & mobile codebase. Sync works on mobile and on the web!

In this version, I have added @versioned markup in GraphQL schema and used API_KEY for aws_appsync_authenticationType. I will try to add @versioned markup to my original project where I am using Cognito user pools and hopefully it will work there.

If anyone else is interested in the working code, I can publish the repo.

Hi @Ashish-Nanda Do you public all latest changes and I can start try testing DataStore?

Hi @Ashish-Nanda Do you public all latest changes and I can start try testing DataStore?

@dimonchik-com Did you try out the steps I mentioned in this comment

I tried out your App, and was able to get it working. The issue is related to your yarn.lock file and dependencies. I've detailed the steps in the linked comment which should resolve your issue. Please let us know if it works for you.

We will be putting out a new release with some improvements this week, but those are not needed to get your app working.

@Ashish-Nanda at the current moment I can't check DataStore problem because when I start check problem with DataStore i unexpectedly encounter with another problem https://github.com/aws-amplify/amplify-js/issues/4942

@davidbiller @danrivett @CarlitosBeto

I tested React Native DataStore on an Expo managed app for both iOS and Android, and it works as expected.

The only difference in instructions is the NetInfo installation and linking step. I have updated the instructions in the original comment to include the steps specific to Expo. Feel free to give it a try and let us know your feedback.

Update!: This now works for me on both Expo as well as Expo web

@Ashish-Nanda Have set this up on Expo as well and it does not seem to be actually saving the data / syncing to the back end, only locally.

When I save a new post, it saves and will query locally without throwing any error. I can't seem to get it to sync with the database at all though when creating new posts. Not sure if I am doing something wrong.

Here are my dependency versions for Amplify:

"@aws-amplify/core": "2.2.5-rn-datastore.3",
"@aws-amplify/datastore": "1.0.7-rn-datastore.3",

Here is my code

Schema:

type Post @model {
  id: ID!
  title: String!
  comments: [Comment] @connection(name: "PostComments")
}

type Comment @model {
  id: ID!
  content: String
  post: Post @connection(name: "PostComments")
}

JavaScript

import React, { useEffect, useState } from "react";
import { Button, Text, View, TextInput } from 'react-native';
global.Buffer = global.Buffer || require('buffer').Buffer

import Amplify from '@aws-amplify/core'
import { DataStore } from "@aws-amplify/datastore";
import { Post } from "./src/models";

import config from './aws-exports'
Amplify.configure(config)

function App() {
  const [form, updateForm] = useState({ title: '' })
  const [posts, updatePosts] = useState([])
  async function query() {
    const postData = await DataStore.query(Post);
    updatePosts(postData)
  }
  async function create() {
    if (!form.title) return
    const postData = { ...form }
    await DataStore.save(
      new Post(postData)
    );
    console.log('successfully created new post')
    updateForm({ title: '' })
    query()
  }
  useEffect(() => {
    query()
  }, []);

  return (
    <View>
      <View style={{marginTop: 200}}>
        <TextInput
          value={form.title}
          placeholder="title"
          style={input}
          onChangeText={val => updateForm({ ...form, 'title': val })}
        />
        <Button onPress={create} title="Create Post" />
      </View>
      {
        posts.map((post, index) => (
          <View key={index}>
            <Text>{post.title}</Text>
          </View>
        ))
      }
    </View>
  );
}

const input = {
  height: 50,
  backgroundColor: '#ddd',
  padding: 10,
  margin: 10
}

export default App;

Have tested both on Expo with iOS and Expo Web

@dabit3 make sure you add @versioned annotation to models. If I remember correctly that was an important bit for me using API token to auth in AppSync. For Cognito User Pool, I had to add @auth annotation too.

@dabit3 Thanks for testing. I'll try out your code and will report back.

@dabit3 make sure you add @versioned annotation to models. If I remember correctly that was an important bit for me using API token to auth in AppSync. For Cognito User Pool, I had to add @auth annotation too.

@edvinasbartkus the @versioned directive should not be used with DataStore. AppSync does this automatically behind the scenes now and in a more comprehensive manner.

Hi All,

We published a new version of React Native DataStore to the @rn-datastore tag that has fixes for some of the known issues.
Go ahead and install the new version as follows to test out the fixes:

npm install -E @aws-amplify/core@rn-datastore @aws-amplify/datastore@rn-datastore 

Here are some more details of the fixes that went into this release:
1) We have fixed the dependency issues with buffer and you can now remove the following line from your app:

global.Buffer = global.Buffer || require('buffer').Buffer

2) We have fixed the issue related to subscriptions failing when you come online. Now if you go offline and then come back online, subscriptions will work, without you needing to kill the app. You can test this on the Android Emulator or on iOS and Android Devices. It may not be possible to test this on iOS simulator due to the following issues with NetInfo: https://github.com/react-native-community/react-native-netinfo/issues/7

3) If you lose connectivity to the network you should no longer get a red screen with the error:
undefined is not an object (evaluating 'this._log.apply')

@Ashish-Nanda thanks for the new version!

I tried to update, but now I do get the following warning on react-native and on the web:

WARN  [WARN] 02:48.579 DataStore - Sync error subscription failed Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onCreateTrip'"}]}

Do I need to do any other updates?

@edvinasbartkus did you make any change on the schema? Can you share your schema so we can reproduce? Thanks!

@edvinasbartkus is your user logged in?

@davidbiller @danrivett @CarlitosBeto

I tested React Native DataStore on an Expo managed app for both iOS and Android, and it works as expected.

The only difference in instructions is the NetInfo installation and linking step. I have updated the instructions in the original comment to include the steps specific to Expo. Feel free to give it a try and let us know your feedback.

thank you @Ashish-Nanda i review the installation and now the project compile, but i force the installation of package with command --save-exact i don´t know the reason but this fix the error.
And now i have other issue:
DataStore - Sync error, subscription failed Connection failed: {"errors":[{"message":"Validation error of type FieldUndefined: Field '_version'
And I couldn't query

@elorzafe no changes for the schema, it was working well with *-rn-datastore.3
I use amazon cognito user identities and the user is logged in.

Here is the schema:

type Trip @model @versioned @auth(rules: [{ allow: owner }]) {
  id: ID!
  name: String!
  places: [Place] @connection(name: "TripPlaces")
}
type Place @model @versioned @auth(rules: [{ allow: owner }]) {
  id: ID!
  title: String!
  method: String
  lng: Float
  lat: Float
  trip: Trip @connection(name: "TripPlaces")
  comments: [Comment] @connection(name: "PlaceComments")
}
type Comment @model @versioned @auth(rules: [{ allow: owner }]) {
  id: ID!
  content: String
  place: Place @connection(name: "PlaceComments")
}

@CarlitosBeto can you share your app on Github, or your schema with us?

@Ashish-Nanda sure, this is my schema:

type Employee
@model
@key(name: "ByEmail", fields: ["email"], queryField: "employeesByEmail") {
id: ID!
createdAt: AWSDateTime
UpdatedAt: AWSDateTime
firstName: String!
lastName: String
fullName: String
dateOfBirth: AWSDateTime
identification: String
email: AWSEmail!
tramite: [Tramite]
@connection(name: "EmployeeTramite", keyField: "inspectorId")
inspectorId: ID
team: Team! @connection(name: "TeamEmployee", keyField: "teamId") #! cambio para compilar mobile
teamId: ID #ID!
rol: Rol @connection(name: "RolEmployee", keyField: "rolId")
rolId: ID
teamMan: Team! @connection(name: "TeamManager", keyField: "teamIdMan") #! cambio para compilar mobile
teamIdMan: ID #ID!
company: Company
@connection(name: "CompanyEmployee", keyField: "companyIdEmp")
companyIdEmp: ID
login: [Login] @connection(name: "EmpleadoLogin")
image: String
cambioEstado: CambioEstado @connection(name: "CambioEstadoEmpleado")
}

type Team @model {
id: ID!
name: String!
employees: [Employee] @connection(name: "TeamEmployee", keyField: "teamId")
teamId: ID
manager: Employee @connection(name: "TeamManager", keyField: "teamIdMan")
teamIdMan: ID!
tramite: [Tramite] @connection(name: "TeamTramite", keyField: "teamId")
}

type Channel @model {
id: ID!
firstName: String!
lastName: String
dateOfBirth: AWSDateTime
email: AWSEmail
}

type Company @model {
id: ID!
name: String!
address: String
logo: String
employees: [Employee]
@connection(name: "CompanyEmployee", keyField: "companyIdEmp")
companyIdEmp: ID
tramite: [Tramite] @connection(name: "CompanyTramite", keyField: "companyId")
companyId: ID
#grupo: Grupo @connection(name: "CompanyGrupo")
}

type Rol @model {
id: ID!
name: String!
empleado: [Employee] @connection(name: "RolEmployee", keyField: "rolId")
products: [Product] @connection(name: "RolProduct", keyField: "rolId")
}

type Product
@model
@key(name: "ByRolId", fields: ["rolId"], queryField: "productByRolId") {
id: ID!
name: String!
menu: AWSJSON
rol: Rol @connection(name: "RolProduct", keyField: "rolId")
rolId: ID
}

type Tramite
@model
@key(
name: "tramiteInspector"
fields: ["inspectorId"]
queryField: "tramiteInspector"
)
@key(
name: "tramiteTipoNum"
fields: ["tipo", "numTramite"]
queryField: "tramiteTipoNum"
) {
#@searchable
id: ID!
createdAt: AWSDateTime
numTramite: String!
oficialNegocio: String
nombreApellido: String
cedula: String
direccion: String
telefonos: String
tipoNegocio: String
destinoCredito: String
afct: String
monto: String
nombreApellido_IN: String
cedula_IN: String
direccion_IN: String
telefonos_IN: String
tipoNegocio_IN: String
destinoCredito_IN: String
afct_IN: String
monto_IN: String
direccionInversion: String
ruralUrbano: String
extension: String
esPropio: Boolean
esGravamen: Boolean
propietario: String
coorUTMZ: String
coorUTML: String
coorUTME: String
coorUTMN: String
uPLat: Float
uPLon: Float
descripcion: String
inventario: String
otrosActivos: String
observaciones: String
nombreApellidosGarante: String
cedulaGarante: String
direccionGarante: String
direccionHipoteca: String
telefonoGarante: String
nombreApellidosGarante_IN: String
cedulaGarante_IN: String
direccionGarante_IN: String
direccionHipoteca_IN: String
telefonoGarante_IN: String
inspector: Employee
@connection(name: "EmployeeTramite", keyField: "inspectorId")
inspectorId: ID
estado: TramiteEstado!
canton: String
provincia: String
agencia: String
regional: RegionalTramite
tipo: TipoTramite!
company: Company @connection(name: "CompanyTramite", keyField: "companyId")
companyId: ID
team: Team @connection(name: "TeamTramite", keyField: "teamId")
teamId: ID
cambioEstado: CambioEstado
@connection(name: "CambioEstadoTramite", keyField: "tramiteId")
observacion: String
grupo: Grupo @connection(name: "GrupoTramite", keyField: "grupoId")
grupoId: ID
imagen: [String]
fechaInspeccion: AWSDateTime
tipoProyecto: String
tipoPropiedad: String
parroquia: String
referencias: String
barrio: String
linderoNorte: String
linderoSur: String
linderoEste: String
linderoOeste: String
edificaciones: String
terreno: String
localComercial: String
infraestructuras: String
riesgosPotenciales: String
inventarioComercial: String
vivienda: String
herramientas: String
terrenos: String
unidadesProductivas: String
vehiculos: String
ingresosDemostrables: String
maquinarias: String
tipoGarantia: String
actEconPer: String
edificacionesHip: String
terrenoHip: String
extHip: String
localComercialHip: String
riesgosPotHip: String
observacionesHip: String
descripcionOtros: String
provinciaUbi: String
direccionUbi: String
cantonUbi: String
parroquiaUbi: String
referenciasUbi: String
barrioUbi: String
coorUTMZUbi: String
coorUTMLUbi: String
coorUTMEUbi: String
coorUTMNUbi: String
linderoNorteUbi: String
linderoSurUbi: String
linderoEsteUbi: String
linderoOesteUbi: String
firmaCliente: String
firmaGarante: String
}

type Login @model {
id: ID!
empleado: Employee @connection(name: "EmpleadoLogin")
fecha: AWSTimestamp
coords: AWSJSON
}

enum RegionalTramite {
IBARRA
QUITO
RIOBAMBA
PORTOVIEJO
GUAYAQUIL
CUENCA
LOJA
}

enum TipoTramite {
INSPECCION
REINSPECCION
VERIFICACION
}

enum TramiteEstado {
CARGADO #SUBE INF AL SISTEMA
AGENDADO #EQUIPO O PROP
REAGENDADO #EQUIPO O PROP /PRIORIDAD UNO
INSPECCION #EN INSPECCIÓN
PROCESANDO #AUN TRABAJO
FINALIZADO #TRABAJO INSP TERMINADO
VALIDANDO #TRABAJO VALIDADOR
CERRADO #LISTO PARA CLIENTE
}

type CambioEstado @model {
id: ID!
createdAt: AWSDateTime
estadoInicial: TramiteEstado
estadoFinal: TramiteEstado
tramite: [Tramite]
@connection(name: "CambioEstadoTramite", keyField: "tramiteId")
tramiteId: ID
usuario: Employee! #! cambio para compilar mobile
@connection(name: "CambioEstadoEmpleado", keyField: "employeeId")
employeeId: ID! #compila mobile
}

type Grupo @model {
id: ID!
createdAt: AWSDateTime
#company: Company @connection(name: "CompanyGrupo")
companyId: ID
nombre: String
tramite: [Tramite] @connection(name: "GrupoTramite", keyField: "grupoId")
grupoId: ID
fechaAsignacion: AWSDateTime
}

type Embarcacion @model {
id: ID!
createdAt: AWSDateTime
nombre: String
contactoPrincipal: String
tramite: String
ci_ruc: String
estadoCallCenter: String
observacion: String
representanteLegal: String
ceduladeIdentidadRL: String
apellidosRL: String
nombresRL: String
provincia: String
canton: String
parroquia: String
telefonoConvencional: String
telefonoMovil: String
correoElectronico: String
nombreEmbarcacion: String
matricula: String
puertoRegistro: String
tipodeNave: String
material: String
esloraTotal: String
esloraConvenio: String
manga: String
puntal: String
calado: String
tonelajeBruto: String
tonelajeNeto: String
valorEmbarcacion: String
totalMotor: String
totalAccesorios: String
totalArtes: String
avaluo: String
fechaAvaluo: String
ValorEmbarcacion: String
Serviciopesca: String
FechaConstruccion: String
FechaRegistro: String
TipoCasco: String
Propulsion: String
TipoCombustible: String
Motor1: String
Tipo1: String
Marca1: String
Modelo1: String
Potencia1: String
Troquelado1: String
Motor2: String
Tipo: String
Marca: String
Modelo: String
Potencia: String
Troquelado: String
GPS: String
Brujula: String
Ecosonda: String
Radio: String
Celular: String
Otros: String
EquiposAuxilio: String
ChalecosSalvavidas: String
LucesBengala: String
Boyasflotadores: String
}

maybe any command like --save-exact or force push into schema in cloud, because i belive this is not refresh

@edvinasbartkus if you switch back to @rn-datastore.3 does it work again? It does not seem like the error you are getting is related to the changes in the datastore client, but we can use that to test if it's a regression.

@CarlitosBeto its possible you have not pushed up your schema changes to AppSync since it is different from your comment here where you had @versioned in your schema.

Can you run the following:
1) Run codegen:

npm run amplify-modelgen

2) Push your changes to the backend:

npm run amplify-push

3) Refresh your app

@Ashish-Nanda, I remove @versioned and refresh but I have the same issue, the change is not work for me.
I though the version is failed but the version of diferents package is ok.
I saw the API file generate in app and the API have fields:
_version
_deleted
_lastChangedAt
version
And remove this fields and app running, therefore i supposed the error is in cloud version for the query.

@CarlitosBeto you should not be manually removing _version, _deleted, _lastChangedAt from any files.
I suggest we try the following. You are using Expo correct?
I can put up a simple expo app with a basic schema and instructions for you to test if queries, mutations and subscriptions work. You can try that and after confirming it works, you can modify it to see if you can get it working with your schema.

Would that be a good next step to help you out?

HI @CarlitosBeto can you DM me on twitter?
https://twitter.com/menyao

Sure I sent a DM from CarlosBetoQ

Here are some tips as I worked through trying to get Auth to work with react-native:

You'll need to run amplify add auth: Here are the answers I used

Using service: Cognito, provided by: awscloudformation
The current configured provider is Amazon Cognito.
Do you want to use the default authentication and security configuration? Manual configuration
Select the authentication/authorization services that you want to use: I want to learn more.
Amazon Cognito identity pools provide temporary AWS credentials for users who are guests (unauthenticated) and for users who have been authenticated and received a token. An identity pool is a store of user identity data specific to your account.
If you choose to use the default configuration, this utility will set up both a Userpool and an Identity Pool.
Select the authentication/authorization services that you want to use: User Sign-Up, Sign-In, connected with AWS IAM controls (Enables per-user Storage features for images or other content, Analytics, and more)
Please provide a friendly name for your resource that will be used to label this category in the project: abrdatstob
Please enter a name for your identity pool. abrdatstob
Allow unauthenticated logins? (Provides scoped down permissions that you can control via AWS IAM) Yes
Do you want to enable 3rd party authentication providers in your identity pool? No
Please provide a name for your user pool: abrdatstob
Warning: you will not be able to edit these selections.
How do you want users to be able to sign in? Email
Do you want to add User Pool Groups? No
Do you want to add an admin queries API? No
Multifactor authentication (MFA) user login options: OFF
Email based user registration/forgot password: Enabled (Requires per-user email entry at registration)
Please specify an email verification subject: Your verification code
Please specify an email verification message: Your verification code is {####}
Do you want to override the default password policy for this User Pool? No
Warning: you will not be able to edit these selections.
What attributes are required for signing up? Email
Specify the app's refresh token expiration period (in days): 365
Do you want to specify the user attributes this app can read and write? No
Do you want to enable any of the following capabilities?
Do you want to use an OAuth flow? No
? Do you want to configure Lambda Triggers for Cognito? No
Successfully added resource abrdatstob locally
Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting categ

then amplify push to make those changes live. Make sure you use SHORT names for things, I've had cloud formation fail because the default proposed name ended up generating IAM role names that were too long. If that happens, do amplify remove auth, amplify push and try adding it again using a shorter name.

Any time after changing your schema.graphql file, e.g. to add an @auth(rules: [{ allow: owner }]) be sure to re run both amplify codegen model and also amplify push to update the schema.js and push those changes to AWS. You can confirm that auth was applied by looking in schema.js at the models.Posts.attributes which should have a new second entry "type": "auth", with other stuff in it. You can confirm that auth is setup in the cloud by logging into AppSync console, heading over to the tables in DynamoDB and you should see an owner column on the table.

Here's my schema

enum PostStatus {
  ACTIVE
  INACTIVE
}

type Post @model @auth(rules: [{ allow: owner }]) {
  id: ID!
  title: String!
  comments: [Comment] @connection(name: "PostComments")
  rating: Int!
  status: PostStatus!
}

type Comment @model @auth(rules: [{ allow: owner }]) {
  id: ID!
  content: String
  post: Post @connection(name: "PostComments")
}

After you add auth you need to delete all the rows from dynamodb. Because the old records won't have owner populated.

Also delete and re-add the app from your iOS simulator. That's because datastore on the simulator will have a cached copy of those deleted records -- which won't have owner properly set either.

Also, you will now need to add Auth to App.js. Here's my App.js based on the javascript sample for DataStore.

global.Buffer = global.Buffer || require('buffer').Buffer

import React, { useEffect, useState } from "react";

import Amplify from "@aws-amplify/core";
import { Authenticator } from 'aws-amplify-react-native';
import { DataStore, Predicates } from "@aws-amplify/datastore";

import { Post, PostStatus } from "./models";

import awsConfig from "../aws-exports";
import { Button, View, Text, ScrollView } from "react-native";
Amplify.configure(awsConfig);

function onCreate() {
  DataStore.save(
    new Post({
      title: `New title ${Date.now()}`,
      rating: (function getRandomInt(min, max) {
        min = Math.ceil(min);
        max = Math.floor(max);
        return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive
      })(1, 7),
      status: PostStatus.ACTIVE
    })
  );
}

function onDeleteAll() {
  DataStore.delete(Post, Predicates.ALL);
}

async function onQuery(setPosts) {
  const posts = await DataStore.query(Post, c => c.rating("gt", 4));
  setPosts(posts)
}

async function listPosts(setPosts) {
  const posts = await DataStore.query(Post, Predicates.ALL);
  setPosts(posts);
}

async function bumpRating(post) {
  const copy = await Post.copyOf(post, p => p.rating = p.rating + 1);
  await DataStore.save(copy);
}

const SignedIn = (p) => {
  const [posts, setPosts] = useState([]);

  useEffect( () => {
    if (p.authState === 'signedIn') {
      listPosts(setPosts);

      const subscription = DataStore.observe(Post).subscribe(msg => {
        console.log(msg.model, msg.opType, msg.element);
        listPosts(setPosts);
      });

      // const handleConnectionChange = () => {
      //   const condition = navigator.onLine ? 'online' : 'offline';
      //   console.log(condition);
      //   if (condition === 'online') { listPosts(setPosts); }
      // }

      // window.addEventListener('online', handleConnectionChange);
      // window.addEventListener('offline', handleConnectionChange);

      return () => subscription.unsubscribe();
    } else {
      DataStore.clear()
    }
  }, [p.authState])

  if (p.authState !== 'signedIn') {
    return null
  }

  return (
    <View style={{margin: 20}}>
      <View>
        <Button title="NEW" onPress={() => { onCreate(); listPosts(setPosts)} } />
        <Button title="DELETE ALL" onPress={() => { onDeleteAll(); listPosts(setPosts)} } />
        <Button title="QUERY rating > 4" onPress={() => { onQuery(setPosts)} } />
        <Button title="ALL POST" onPress={() => { listPosts(setPosts)} } />
      </View>
      <ScrollView>
          {posts.map( (item,i) => {
            return <View key={i}>
              <Text>id: {posts[i].id.substring(0,8)}</Text>
              <Text>title: {posts[i].title}</Text>
              <Text>rating: {posts[i].rating}</Text>
              <Text>_version: {posts[i]._version}</Text>
              <Button title="Increase Rating" onPress={() => bumpRating(posts[i])}/>
            </View>
          } )}
      </ScrollView>
    </View>
  )
}

function App() {
  return (
    <Authenticator>
      <SignedIn />
    </Authenticator>
  );
}

export default App;

@paddlefish thanks for your detailed example. Glad you were able to get it working.

Amplify DataStore for React Native is now released

Hi All
We just released Amplify DataStore for React Native to @latest.
You can now simply do:

npm i @aws-amplify/core @aws-amplify/datastore

Please give it a try. You can find the updated Docs here: https://aws-amplify.github.io/docs/js/datastore

Thank you for helping us test the pre-release versions and we look forward to your feedback.

Closing this feature request now that the feature has been delivered.

For expo users
Just commenting here in case that people are running on the same issue.

@aws-amplify/datastore requires expo 36 since react-native-netinfo >= 4.x.x requires react native >= 0.60

@Ashish-Nanda maybe worth to mention on the official docs?

Can I observe for a particular keyId? What I mean, is it possible to filter the data on observe?
Something link onCreateComment(postId: ID!)?

@subhendukundu Yes, check out the docs here

Does DataStore work for an AppSync API whos main data source is a lambda connecting to a AWS Neptune cluster? All the documentation seems to assume you're using DynamoDB and it seems the offline features (conflict resolution and delta sync) are only really suited for DynamoDB. I wanted to use DataStore for offline requirements because using the default AppSync method with Apollo Client seems to have issues since the release of Apollo 3.x.

Was this page helpful?
0 / 5 - 0 ratings