Apollo-client: __typename in query response

Created on 17 Jul 2017  路  26Comments  路  Source: apollographql/apollo-client

When I use next query

videoQuiz(slug: $slug) {
      id
      slug
      title
    }

I get next response:

{
   id: ...
   slug: ...
   title: ...
   __typename: ...
}

I know and understand that apollo-client will add __typename automatically into the query. But my question is if it is all right that I will get it in my response. Currently I am using this object as input for mutation which is defined as

 myMutation(input: MyInput): MyPayload

input MyInput {
  id
  slug
  title
}

And therefore I need to remove __typename for each mutation.
I do not want to complain. I am just asking if it is feature or bug.

鈦夛笍 question 鉁嶏笍 working-as-designed

Most helpful comment

To stop adding __typename by default in the queries/mutations, addTypename field must be set to false in the InMemoryCache constructor.

const client = new ApolloClient({
  link: new HttpLink({uri: MY_URL}),
  cache: new InMemoryCache({
    addTypename: false
  })
});

All 26 comments

@seeden it is the intended default behavior. Apollo Client uses __typename in order to determine a data id when handling cache updates (https://github.com/apollographql/apollo-client/blob/master/src/ApolloClient.ts#L85-L95). It also is helpful to not strip them to the end result for doing optimistic updates based on previous data since __typename is part of that response data!

I hope this was helpful! If not, please feel free to reopen the issue and we can keep discussing it 馃憤

Sorry for reopening, but it doesn't make sense to me. You can't mutate with __typename key name otherwise you need to include it inside of your schema on each nested object.

@jbaxleyiii Agreed with @mhlavacka, this field breaks my mutations.

I am having same problem. I am parsing long list of data and at the end i have to test for __typename and remove it manually every time. That is huge waste of time... any solutions to remove this from query ?

You can remove it by adding addTypename: false in your Apolloclient init:

const client = new ApolloClient({
  networkInterface,
  addTypename: false
});

@jbaxleyiii It would be useful to know exactly the consequences of turning this off. I can't quite piece it together from the various issues on the topic. I'm assuming turning this off will break caching in some way?

To stop adding __typename by default in the queries/mutations, addTypename field must be set to false in the InMemoryCache constructor.

const client = new ApolloClient({
  link: new HttpLink({uri: MY_URL}),
  cache: new InMemoryCache({
    addTypename: false
  })
});

Does anybody have a script to remove __typename from nested object of Query response?

@Access2emma you can use https://github.com/jonschlinkert/omit-deep like so:

omitDeep(data, '__typename')

I'd recommend against introducing a dependency just to do this:

const omitTypename = (key, value) => (key === '__typename' ? undefined : value)
const newPayload = JSON.parse(JSON.stringify(payload), omitTypename)

As far as setting the addTypename option in the InMemoryCache to false, my understanding is that this will negatively affect cache performance, but I haven't dug in deep enough to know the consequences.

Can anyone from the apollo team chime in here, either by explaining the consequences, or linking some documentation? The readme states:

If id and _id are not specified, or if __typename is not specified, InMemoryCache will fall back to the path to the object in the query, such as ROOT_QUERY.allPeople.0 for the first record returned on the allPeople root query.

It's not really clear what the performace impact is here.

If you're using apollo-boost, then it looks like this...

import ApolloClient from "apollo-boost";
import { InMemoryCache } from 'apollo-cache-inmemory';

export default new ApolloClient({
    uri: "http://localhost:8030/graphql",
    cache: new InMemoryCache({
        addTypename: false
    })
});

If you're using graphql HOC/decorator from react-apollo and want to avoid having to manually remove __typename from every response, you can just require this module https://www.npmjs.com/package/typename-monkey-patch somewhere near the entry point of your app.
It monkey patches the graphql HOC from react-apollo so that __typename is filtered out before sending data to your wrapped component.

Note that setting addTypename to false makes fragments unusable and breaks apollo's cache state normalization.

Just a note on using the JSON.stringify() solution from @danderson00 - if you want to do file uploads and you use something like apollo-upload-client then the serialization-parse step will destroy your reference to the File object and the upload will not work.

Combining solutions from a few places (including @danderson00 and this readme):

import { ApolloClient } from 'apollo-client';
import { ApolloLink, from } from 'apollo-link';
import link from './link';

// Strip __typename from variables
const middleWareLink = new ApolloLink((operation, forward) => {
  if (operation.variables) {
    const omitTypename = (key, value) => (key === '__typename' ? undefined : value);
    // eslint-disable-next-line no-param-reassign
    operation.variables = JSON.parse(JSON.stringify(operation.variables), omitTypename);
  }
  return forward(operation);
});

export default new ApolloClient({
  link: from([
    middleWareLink,
    link,
  ]),
});

in Angular JS
import ApolloClient from "apollo-boost";
import { InMemoryCache } from 'apollo-cache-inmemory';

export default new ApolloClient({
uri: "http://localhost:8030/graphql",
cache: new InMemoryCache({
addTypename: false
})
});

how to do in androdi please help...

It would make sense to have __typename be a Symbol. That way you expose metadata without doing it inband and confusing code which just wants to deal in data.

Setting addTypename: false does screw up my schema, is it worth it to instead just remove __typename from data props as results of <Query>?

Hi All

https://stackoverflow.com/questions/47211778/cleaning-unwanted-fields-from-graphql-responses/51380645#51380645

In the above thread, I have posted the answer for this problem please refer to it.

Please let me know if it works for you.

Regards
Rigin Oommen

Man, this is a dumb problem to be dealing with.

Man, this is a dumb problem to be dealing with.

Then please suggest the optimal solution.

The reason __typename is included in response objects is that folks frequently update those objects and write them back into the store, and the cache would behave differently if it could not rely on receiving the same __typename that it previously saw. Specifically, __typename information is crucial for computing an ID for the object, so that the cache knows you're referring to the same entity as before, rather than some new, unidentifiable entity.

I have tried multiple times to exclude unwanted __typename fields from result objects (#5311, #5154), but I have since become convinced that they are necessary: #5320. This position is not likely to change unless someone who fully understands the problem comes up with a better solution than I have been able to find.

Making __typename non-enumerable is possible, but the mere presence of non-enumerable properties slows down all operations on the object (thanks JavaScript!). Otherwise, I would be happy to hide this behavior just so people would stop complaining.

Specifically, __typename information is crucial for computing an ID for the object, so that the cache knows you're referring to the same entity as before, rather than some new, unidentifiable entity.

Perhaps a silly question, but if all id fields in the schema are UUIDs, does that make __typename unnecessary? Could this property be used somehow?

What about this case: I am trying to set initial data in local cache, sth like this:

client.cache.writeData({ data: { isLoggedIn: !!window.localStorage.getItem('token'), cartItems: [], params: { name: 'test' } } })

And I've got warning that __typename is missing from params and when I add it then warning disappears and I've got correct response. But my question would be: Should I assign value(something unique) by myself? sth like this :

client.cache.writeData({ data: { isLoggedIn: !!window.localStorage.getItem('token'), cartItems: [], params: { name: 'test', __typename: 'params_unique_test' } } })

Specifically, __typename information is crucial for computing an ID for the object, so that the cache knows you're referring to the same entity as before, rather than some new, unidentifiable entity.

Perhaps a silly question, but if all id fields in the schema are UUIDs, does that make __typename unnecessary? Could this property be used somehow?

The ID doesn't need to be a uuid. It just needs to be unique to the type of object. You can technically have a user object with ID 1, another with ID 2, and also have a list object with ID 1, another with ID 2.

Specifically, __typename information is crucial for computing an ID for the object, so that the cache knows you're referring to the same entity as before, rather than some new, unidentifiable entity.

Perhaps a silly question, but if all id fields in the schema are UUIDs, does that make __typename unnecessary? Could this property be used somehow?

The ID doesn't need to be a uuid. It just needs to be unique to the type of object. You can technically have a user object with ID 1, another with ID 2, and also have a list object with ID 1, another with ID 2.

Yes, the ID doesn't _have_ to be a UUID, but I think what @vlindhol is getting at is _if_ all your ID are UUIDs then maybe we don't need __typename for the cache to work correctly.

I'd recommend against introducing a dependency just to do this:

const omitTypename = (key, value) => (key === '__typename' ? undefined : value)
const newPayload = JSON.parse(JSON.stringify(payload), omitTypename)

As far as setting the addTypename option in the InMemoryCache to false, my understanding is that this will negatively affect cache performance, but I haven't dug in deep enough to know the consequences.

Can anyone from the apollo team chime in here, either by explaining the consequences, or linking some documentation? The readme states:

If id and _id are not specified, or if __typename is not specified, InMemoryCache will fall back to the path to the object in the query, such as ROOT_QUERY.allPeople.0 for the first record returned on the allPeople root query.

It's not really clear what the performace impact is here.

The only problem with this approach is that it will break file uploads. Because we need the File object and when you stringify we will lose information for the upload

Was this page helpful?
0 / 5 - 0 ratings