Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent data between apollo client and server/playground #11317

Closed
PatrickJung94 opened this issue Oct 25, 2023 · 6 comments
Closed

Inconsistent data between apollo client and server/playground #11317

PatrickJung94 opened this issue Oct 25, 2023 · 6 comments

Comments

@PatrickJung94
Copy link

PatrickJung94 commented Oct 25, 2023

Issue Description

When using Graphql and Apollo Client in our project I came across an issue that is not resulting in an error and thus provides us with inconsistent data. I understood that this issue is created by us in the end, though I think that apollo client should provide us with an error in this case if it is possible.

There seems to a problem with data assigning in the apollo client because when I tested the query it is working in the playground and using a standard fetch request was also getting me the correct data.

I am using Golang for the backend and an Angular app for the frontend. Both are using graphql codegen to generate the types and queries/mutations.

github.com/99designs/gqlgen: v0.17.22

apollo-angular: ^5.0.0

graphql: ^16.8.0

@apollo/client: ^3.7.15

I have also checked previous issues and they didnt seem to match my findings exactly: #9850 or #3234

Link to Reproduction

No specific link for reproduction

Reproduction Steps

I have a type setup that looks like this:

type TestCount {
  testcase: Testcase!
  testCount: Int!
}

type Testcase {
  id: ID!
  name: String!
  type: String!
}

extend type Query {
  getTestCounts(): [TestCount!]!
}

When doing the query in the play ground it would look like this:

query {
  getTestCounts {
    testcase {
      id
      name
      type
    }
    testCount
  }
}

The result would be similar to this:

{
  "data": {
    "getTestCounts": [
      {
        "testcase": {
          "id": "",
          "name": "Testing for the bug",
          "type": "Text"
        },
        "testCount": 100
      },
      {
        "testcase": {
          "id": "",
          "name": "Different case",
          "type": "Automated"
        },
        "testCount": 123
      },
      {
        "testcase": {
          "id": "",
          "name": "A different kind of test",
          "type": "Manual"
        },
        "testCount": 251
      }
    ]
  }
}

Now to the problematic set up. I did the query in the backend where I made a object that would only include the necessary field I need to form a unique name name and type. Since I used the code generated DTOs I made a dto with just these two fields.

var testcase = &dto.Testcase{
  Name: tc.Name,
  Type: tc.Type,
}

As one could see the query in the playground wants to get an ID as well which is a valid action to do so in the playground I get ID as an empty string, however when I make the same query with the Apollo client I get weird behaviour. The data in the network tab from the browser shows the correct data but if I log out the data from the result of the query I get different data.

Data from network tab:

{
  "data": {
    "getTestCounts": [
      {
        "testcase": {
          "id": "",
          "name": "Testing for the bug",
          "type": "Text"
        },
        "testCount": 100
      },
      {
        "testcase": {
          "id": "",
          "name": "Different case",
          "type": "Automated"
        },
        "testCount": 123
      },
      {
        "testcase": {
          "id": "",
          "name": "A different kind of test",
          "type": "Manual"
        },
        "testCount": 251
      }
    ]
  }
}

Data from query:

{
  "data": {
    "getTestCounts": [
      {
        "testcase": {
          "id": "",
          "name": "Testing for the bug",
          "type": "Text"
        },
        "testCount": 100
      },
      {
        "testcase": {
          "id": "",
          "name": "Testing for the bug",
          "type": "Text"
        },
        "testCount": 123
      },
      {
        "testcase": {
          "id": "",
          "name": "Testing for the bug",
          "type": "Text"
        },
        "testCount": 251
      }
    ]
  }
}

As one can see the data is not consistent with the data from the network tab. I think this is because the apollo client is using the ID to assign the data to the correct object. Since the ID is empty it is assigning the data to the first object it can find. But since I request the ID but not provide it from the backend side it is empty and techincally it is not an error since one can freely choose what to request with graphql. I feel like there should be an error at some point so this cannot happen, either when using the genreated code or when doing the query.

My solution is to just correctly provide the ID or do not request the ID at all.

@phryneas
Copy link
Member

phryneas commented Oct 25, 2023

Apollo Client is a normalized cache - by default it uses __typename and id for that.

So everything with the combination Testcase and "" in this case is seen as "the same object" by the cache.

You could use another method of uniquely identifying your objects (see customizing cache ids).

Generally, this is expected behaviour - you are breaking underlying assumptions here - e.g. the GraphQL standard describes the ID type as "unique identifier" - your ids are not identifying anything.

@PatrickJung94
Copy link
Author

Is that also the case if I am using network-only in the setup of our client?

defaultOptions: {
  watchQuery: {
    fetchPolicy: 'network-only',
  },
  query: {
    fetchPolicy: 'network-only',
  },
  mutate: {
    fetchPolicy: 'network-only',
  },
},

@phryneas
Copy link
Member

It would be no-cache. But really, please just don't do this! You lose out on all features of a normalized cache - e.g. a mutation updating your queries without having to re-fire those.

Please give your entities real identifiers!

@PatrickJung94
Copy link
Author

Yes I will use it correctly now since I understand the way the client will associate the objects, it was just an issue for me since I spent a day trying to figure out why this was happening and I felt like one could use feedback when this happens. Maybe a warning would be enough.

The network-only was a solution to a different problem but I will need to test no-cache or other settings to see if I still come up with the issue.

@bignimbus
Copy link
Contributor

@PatrickJung94 thanks for the feedback! I'm closing this issue but please feel free to take a look at our docs and let us know where we could be more clear about best practices with the cache 🙏🏻

Copy link
Contributor

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
For general questions, we recommend using StackOverflow or our discord server.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 30, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants