awslabs / aws-mobile-appsync-sdk-js

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

buildMutation not working properly #349

Open flybayer opened 5 years ago

flybayer commented 5 years ago

I'm trying to use buildMutation, and it doesn't seem to be working correctly. I'm also confused by the discrepancy between docs and source.

The Amplify API docs say to do this:

  const result = await client.mutate(buildMutation(client,
    gql(createStudent),
    {
      inputType: gql(CreateStudentInput),
      variables
    },
    (_variables) => [ gql(listStudents) ],
    'Student'
  ));

but by looking at the source code it looks like I should do this:

  const result = await client.mutate(buildMutation(
      client,
      gql(createStudent),
      variables,
      gql(listStudents),
      'Student'
  ))

Here's what happens using the second code sample

  1. I initiate create on a Student named 'Bob'

  2. (In another component) The listStudents query returns an empty data.listStudents while the mutation is in flight.

  3. Once the server returns success, then listStudents returns a full data.listStudents including the new record.

  4. Console shows a bunch of errors like

    Missing field bookMaps in {
    "__typename": "Student",
    "id": "30128546-4592-4833-852f-1bdddba858ce",
    "firstName": "Bob"
My `createStudent` mutation ```gql export const createStudent = `mutation CreateStudent($input: CreateStudentInput!) { createStudent(input: $input) { id firstName lastName birthdate curriculumMaps { items { id } nextToken } bookMaps { items { id } nextToken } resourceMaps { items { id } nextToken } summaryMaps { items { id } nextToken } } }` ```

My `listStudents` query ```gql export const listStudents = `query ListStudents( $filter: ModelStudentFilterInput $limit: Int $nextToken: String ) { listStudents(filter: $filter, limit: $limit, nextToken: $nextToken) { items { id firstName lastName birthdate curriculumMaps { nextToken } bookMaps { nextToken } resourceMaps { nextToken } summaryMaps { nextToken } } nextToken } } ` ```

Versions

"aws-appsync": "1.7.1",
"aws-appsync-react": "1.2.6",
manueliglesias commented 5 years ago

Hi @flybayer

The source code you linked is not the one for the aws-appsync version you are using, this is the correct one, it should be in sync with the docs (let me know if it isn't)

https://github.com/awslabs/aws-mobile-appsync-sdk-js/blob/aws-appsync%401.7.1/packages/aws-appsync/src/helpers/offline.ts#L272

flybayer commented 5 years ago

What the world... not sure how I got hold of that old link!

Here's what happens using the code from the docs:

  1. I don't get the empty data.listStudents while the request is in flight, but I do still get the Missing field bookMaps in ... errors.

  2. Cache is never updated, even after successful API response. When offline, the mutation returns an optimistic response success, but the cache is not updated. Also when going back online, the request is never sent to the server.

Lastly, the buildMutation API as documented is extremely confusing. Is there any way the API can be simplified? At the very, very least, it would help to have it fully documented (like what is (_variables) => [ gql(listStudents) ] ??)

Thanks

Edited 2/4/18: cache is actually never updated

4ext commented 5 years ago

At the very, very least, it would help to have it fully documented (like what is (_variables) => [ gql(listStudents) ] ??)

I'm struggling with this as well. The opportunistic part doesn't seem to do anything. It's unfortunate that there doesn't seem to be a full (accurate up to date) example.

Also the docs point to this which only lists "graphqlMutation" specifically for react, with no mention of buildMutation at all.

flybayer commented 5 years ago

And just for the record, I need to use buildMutation instead of graphqlMutation because graphqlMutation doesn't work with react hooks.

flybayer commented 5 years ago

Update: buildMutation is never updating the cache, even after a successful API response. I thought this was working earlier, but I forgot to comment out my refetch() while testing this.

ffxsam commented 5 years ago

I wonder if this is related to #364? Delete mutation executes, but the cache is not updated.

StefanV85 commented 5 years ago

Update: buildMutation is never updating the cache, even after a successful API response. I thought this was working earlier, but I forgot to comment out my refetch() while testing this.

I made the same experience. it updates the cache when i write do not use Arrays in the _variables

Like: ` var tmp = buildMutation( client, gql(createTodo), { inputType: gql(createTodoInput), variables: { input: { name: todoName.value } } }, _variables => gql(listTodos), "Todo" ); const result = await client.mutate(tmp);

`

kjlis commented 5 years ago

For me it also works only if I provide a single query to update - the documentation is quite misleading. Plus it fails if item is missing any of the optional fields (in my case it was an array from @connection directive that was not yet created).

It takes way too much effort and guessing-game to make it work, especially that using helpers is the recommended way to use the mutation - and by the way, the AWS Amplify documentation still points to https://github.com/awslabs/aws-mobile-appsync-sdk-js/blob/master/OFFLINE_HELPERS.md, 5 months after opening this ticket...

@elorzafe any outcome from the investigation? Maybe a simple example (in Typescript if possible) and doc update would be sufficient?

apoorvmote commented 5 years ago

I made the same experience. it updates the cache when i write do not use Arrays in the _variables

It doesn't update the cache with array or without array. Without array example

const response = await client.mutate(buildMutation(client, gql(createTodo), 
      {
        inputType: gql(`input CreateTodoInput {
          id: ID
          name: String!
        }`),
        variables,
      },
      (_variables: any) => gql(listTodos), 'Todo'))

With Array example

const response = await client.mutate(buildMutation(client, gql(createTodo), 
      {
        inputType: gql(`input CreateTodoInput {
          id: ID
          name: String!
        }`),
        variables,
      },
      (_variables: any) => [gql(listTodos)], 'Todo'))
santi8194 commented 4 years ago

Any update here? It's been a year and a half since this issue has any comments. And today, I'm having the same problems, the documentation is the same and I can't find any solution.

PeteDuncanson commented 2 years ago

Another 18 months on, still an issue.