awslabs / aws-mobile-appsync-sdk-js

JavaScript library files for Offline, Sync, Sigv4. includes support for React Native
Apache License 2.0
921 stars 266 forks source link

Mutations not returning any data or errors from AppSync server [Reproducible Repo Included] #256

Closed Austint30 closed 5 years ago

Austint30 commented 6 years ago

EDIT: I have created a repository here where I was able to reproduce the issue on a small-scale project.

I am trying to use the AWSAppsyncClient in my React web application and I have come across an issue that I have been trying to solve for days to no avail.

I cannot seem to be able to return any data from any of the Mutations I have written. I have tested all of my mutations on the AppSync console and I can confirm all of them do return data and errors. The problem seems to lie within the Client itself (or maybe something is wrong with my setup).

For example, when I call this deleteEntity Mutation I want to display the error message to the screen.

<Mutation 
    mutation={DELETE_ENTITY}
    variables={{ _id: record._id, tpID: this.props.orgData.transporter._id }}
    onCompleted={(data) => {console.log('delete data', data); message.success(`Delete successful (${data.deleteEntity})`)}}
    onError={(error) => {console.error(error); message.error('Delete failed: ' + error.message)}}
    refetchQueries={[
        {query, variables: {tpID: this.props.orgData.transporter._id}}
    ]}
    >
{
    (deleteEntity) => (
    <Tooltip title="Delete">
        <Popconfirm placement="left" title="Are you sure you want to delete this?" okText="Delete" onConfirm={() => deleteE
            <Button type="danger" size="small" shape="circle" icon="delete" />
        </Popconfirm>
    </Tooltip>
    )
}
</Mutation>

For this, and all similar mutations, no matter what, the data.mutationName returned from the mutation is always null, and error is always undefined even though this mutations do return data on the AppSync console. This even affects the onError callback function that the react-apollo Mutation component offers.

In my Client setup, I have included an error link as per the Apollo docs so I can see the errors in the console.

When any mutation is run, I do get GraphQL errors in the console like so: image

It seems that somehow these errors are failing to make it back to the Mutation component.

Here is how I am setting up the AppSync Client:

const stateLink = withClientState({
  cache,
  defaults,
  resolvers: _.merge(transporterResolv, contractsResolv, organizationResolv, customerResolv),
  typeDefs: _.concat(transporterSchem, customerSchem)
});

const appSyncLink = createAppSyncLink({
  ...config.appSync,
  auth: {
    ...config.appSync.auth,
    jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken(),
  },
  disableOffline: true
});

const errorLink = onError(({ graphQLErrors, networkError, operation, forward }) => {
    if (graphQLErrors) {
      for (let err of graphQLErrors) {
          console.log('[Graphql Error]', err);
        switch (err.errorType) {
          case 'UnauthorizedException':
            // error code is set to UNAUTHENTICATED
            // when AuthenticationError thrown in resolver

            // modify the operation context with a new token
            return new Observable(async observer => {
                try{
                    // const creds = await Auth.currentUserCredentials();
                    // creds.refresh(err => {throw Error(err)});
                    const idToken = await Auth.currentSession().idToken;
                    console.log('currentSession', await Auth.currentSession());
                    const oldHeaders = operation.getContext().headers;
                    operation.setContext({
                        headers: {
                            ...oldHeaders,
                            authorization: idToken.jwtToken,
                        },
                    });
                    const subscriber = {
                        next: observer.next.bind(observer),
                        error: observer.error.bind(observer),
                        complete: observer.complete.bind(observer)
                    }
                    forward(operation).subscribe(subscriber);
                }catch(error){
                    console.error('ID Token refresh failed', err)
                    observer.error(error)
                }
            })
        }
      }
    }
    if (networkError) {
      console.log(`[Network error]: ${networkError}`);
    }
  }
);

const link = ApolloLink.from([errorLink, stateLink, appSyncLink])

const AppSyncClientOptions = {
    link
}

const client = new AWSAppsyncClient({}, AppSyncClientOptions);

Dependencies from packages.json

"dependencies": {
    "antd": "^3.7.2",
    "apollo-boost": "^0.1.15",
    "apollo-cache-inmemory": "^1.2.9",
    "apollo-link": "^1.2.2",
    "apollo-link-error": "^1.1.0",
    "apollo-link-state": "^0.4.1",
    "aws-amplify": "^1.0.2",
    "aws-appsync": "^1.3.4",
    "aws-appsync-react": "^1.1.4",
    "aws-sdk": "^2.302.0",
    "graphql": "^0.13.2",
    "graphql-tag": "^2.9.2",
    "lodash": "^4.17.10",
    "moment": "^2.22.2",
    "qs": "^6.5.2",
    "react": "^16.4.1",
    "react-apollo": "^2.1.11",
    "react-dom": "^16.4.1",
    "react-router-dom": "^4.3.1",
    "react-scripts": "1.1.4",
    "redux": "^4.0.0",
    "redux-persist": "^5.10.0"
  },
elorzafe commented 6 years ago

@Austint30 did you try just initializing the client like this?

const client = new AWSAppSyncClient({
  url: AppSyncConfig.graphqlEndpoint,
  region: AppSyncConfig.region,
  auth: {
    type: AppSyncConfig.authenticationType,
    apiKey: AppSyncConfig.apiKey,
    // jwtToken: async () => token, // Required when you use Cognito UserPools OR OpenID Connect. token object is obtained previously
  }
});

and also are you wrapping your app with apollo provider like this

const WithProvider = () => (
  <ApolloProvider client={client}>
    <Rehydrated>
      <App />
    </Rehydrated>
  </ApolloProvider>
)

export default WithProvider

Let me know how it goes

alexfedin commented 6 years ago

this happens to me too and this is the client initialization I use:

`export default class App extends Component { render() { return (

);

} }`

Austint30 commented 6 years ago

@elorzafe I have created a repository here where I was able to reproduce the issue on a small-scale project.

jrounsav commented 6 years ago

I was seeing this as well. Had to set disableOffline to true on the client.

Austint30 commented 6 years ago

@jrounsav Thanks for the workaround. Setting disableOffline to true does solve the problem. I was actually already setting disableOffline to true, but I was putting it in the createAppSyncLink instead of the AWSAppSyncClient options.

This works

const client = new AWSAppsyncClient({
    disableOffline: true
}, { link });
philohelp commented 6 years ago

The docs should mention that appsync does not currently support offline. I spent almost 48 hours trying to figure what I was doing wrong.

Envoyé de mon iPhone

Le 25 sept. 2018 à 17:41, Austint30 notifications@github.com a écrit :

@jrounsav Thanks for the workaround. Setting disableOffline to true does solve the problem. I was actually already setting disableOffline to true, but I was putting it in the createAppSyncLink instead of the AWSAppSyncClient options.

This works

const client = new AWSAppsyncClient({ disableOffline: true }, { link }); — You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

Austint30 commented 5 years ago

The docs should mention that appsync does not currently support offline. I spent almost 48 hours trying to figure what I was doing wrong. Envoyé de mon iPhone

Same with me. I gave up after a couple of days and just temporarily treated all of my mutations as a success until a further solution was found.

Jayphen commented 5 years ago

I also had this issue, before realising it was due to the offline behaviour.

I found that the mutation's child function was called twice - once with no data, and then again with the response from the server. If I remember correctly, using an optimistic response avoided the issue (the first time the child fn is called, it would be with the optimistic response).

As far as I can tell, this issue is undocumented

philohelp commented 5 years ago

I tested the same code with AWS and GraphCool backend. Optimistic update does not help. The first update (from local data) is correct, but then the response from the server seems to void the request and the data turns undefined.

Le jeu. 27 sept. 2018 à 11:23, Jayphen notifications@github.com a écrit :

I also had this issue, before realising it was due to the offline behaviour.

I found that the mutation's child function was called twice - once with no data, and then again with the response from the server. If I remember correctly, using an optimistic response avoided the issue (the first time the child fn is called, it would be with the optimistic response).

As far as I can tell, this issue is undocumented

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/awslabs/aws-mobile-appsync-sdk-js/issues/256#issuecomment-425021895, or mute the thread https://github.com/notifications/unsubscribe-auth/AMCgWy-PCv4zRXw8nltQMVb-Xj1eyBuCks5ufJkGgaJpZM4WuwB4 .

elorzafe commented 5 years ago

@Austint30 thanks for sharing your repo. I will clone it now and see what is going on.

I can confirm that this sample using aws-appsync@1.3.4 has queries, mutation and subscriptions working.

elorzafe commented 5 years ago

@Jayphen Thanks for your feedback, we will try to clarify that on our documentation.

elorzafe commented 5 years ago

@philohelp AppSync client supports offline, I just tested this sample app with aws-appsync@1.3.4 and works without issues, do you have a code snippet on how you are configuring and using the client?

elorzafe commented 5 years ago

@Austint30 I've tested your app code and could reproduced the problem. I will root cause the problem now. Thanks for creating the issue.

elorzafe commented 5 years ago

@Austint30 @MentalBrake @jrounsav can you try installing aws-appsync@deepdish-next (current version is 1.3.5-link-effect.2)

I've test @Austint30 sample code and has the expected result.

elorzafe commented 5 years ago

We have fixed this on the latest release (aws-appsync@1.4.0) I will close the issue for now, but feel free to create a new issue if this problem persist.

HuguesRousseau commented 5 years ago

Hi, I reproduce the problem using Angular 7, "aws-appsync": "^1.7.1", with enableProdMode(). Using disableOffline: true makes the problem go away. Is it possible the problem is not fixed with Angular 7?

mamach86 commented 5 years ago

Hi all, same problem here but with queries ("aws-appsync": "^1.7.2") : with disableOffline: true works like a charm, but when I try enabling offline and making queries with fetchPolicy:"cache-first" I get a null value returned in the data.queryName object returned from the query, most of the time but not always (sometimes it works). I don't get why the behaviour is different when the cache is hit and does not return value, the behaviour should be the same as having offline disabled right ? Here it seems for som reason that when the cache returns nothing the query does not really try to fetch data from the server.

Any update on this ? Thanks a lot

mamach86 commented 5 years ago

We have fixed this on the latest release (aws-appsync@1.4.0) I will close the issue for now, but feel free to create a new issue if this problem persist.

Hi @elorzafe , I'm having similar issues but with queries (see my post above). By any chance, do you have news about this ?

Thanks a lot

mzdon commented 5 years ago

I was facing this same issue for a while until I found that there was a mismatch between the data I was sending to the server and the graphql input type defined in our AWS AppSync schema!

Our input type had fields that were arrays of strings or arrays of the AWSJSON data type and I was accidentally sending an empty string in one of those fields which caused data creation/persistence to fail and in turn the server was ALWAYS returning null instead of all the fields I expected to get back from the mutation.

I would imagine this could affect both queries and mutations if the data types your input doesn't match EXACTLY what the schema defines and is not an issue with the aws appsync sdk itself.

It's too bad the server doesn't throw any exceptions. I suspect quite a few developers are seeing this behavior which is caused by a data to schema mismatch and an error response from the server would make that issue clear as day. Maybe those errors are being buried somewhere due to our resolvers...

akhilvc10 commented 4 years ago

I was facing this same issue for a while until I found that there was a mismatch between the data I was sending to the server and the graphql input type defined in our AWS AppSync schema!

Our input type had fields that were arrays of strings or arrays of the AWSJSON data type and I was accidentally sending an empty string in one of those fields which caused data creation/persistence to fail and in turn the server was ALWAYS returning null instead of all the fields I expected to get back from the mutation.

I would imagine this could affect both queries and mutations if the data types your input doesn't match EXACTLY what the schema defines and is not an issue with the aws appsync sdk itself.

It's too bad the server doesn't throw any exceptions. I suspect quite a few developers are seeing this behavior which is caused by a data to schema mismatch and an error response from the server would make that issue clear as day. Maybe those errors are being buried somewhere due to our resolvers...

Facing the same issue. Update mutation not working. It doesn't throw any errors. What would be the possible cause for this ?

Thank alot

nayanbhana commented 4 years ago

I was just going crazy wondering why my mutation was not invoking! Then finally I saw an error in my console backend.js:6 TypeError: observer.error is not a function. This lead me to here, and I added disableOffline: true to my config and my mutation was successfully invoking again.

anthonyhumphreys commented 4 years ago

@elorzafe this still seems to be an issue in 3.0.2 - only way i can get mutations to work is with disableOffline:true