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

__typename in query response #1913

Closed
seeden opened this issue Jul 17, 2017 · 30 comments
Closed

__typename in query response #1913

seeden opened this issue Jul 17, 2017 · 30 comments

Comments

@seeden
Copy link
Contributor

seeden commented Jul 17, 2017

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.

@jbaxleyiii
Copy link
Contributor

@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 👍

@matthlavacka
Copy link

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.

@jjant
Copy link

jjant commented Sep 25, 2017

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

@Dishant15
Copy link

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 ?

@matthlavacka
Copy link

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

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

@danderson00
Copy link

@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?

@wawhal
Copy link

wawhal commented Mar 21, 2018

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
  })
});

@neyosoft
Copy link

neyosoft commented May 1, 2018

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

@capaj
Copy link
Contributor

capaj commented May 31, 2018

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

omitDeep(data, '__typename')

@danderson00
Copy link

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.

@mnpenner
Copy link

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
    })
});

@ikatun
Copy link

ikatun commented Jul 28, 2018

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.

@michaelbromley
Copy link

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.

@arist0tl3
Copy link

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,
  ]),
});

@Nitishreddy787
Copy 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...

@tahoemph
Copy link

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.

@itsnotrisky
Copy link

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

@riginoommen
Copy link

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

@simkessy

This comment has been minimized.

@riginoommen
Copy link

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

Then please suggest the optimal solution.

@benjamn
Copy link
Member

benjamn commented Jan 23, 2020

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.

@vlindhol
Copy link

vlindhol commented Feb 7, 2020

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?

@vanoMekantsishvili
Copy link

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' } } })

@ljmerza
Copy link

ljmerza commented May 13, 2020

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.

@vjdw
Copy link

vjdw commented Aug 12, 2020

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.

@guilhermeKodama
Copy link

guilhermeKodama commented Sep 5, 2020

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

@luizcarlos1405
Copy link

If only the mutations would accept the __typename field or automatically strip it for us instead of complaining that it's there...

@AWolf81
Copy link

AWolf81 commented Jan 16, 2022

I've tried the omitDeep that was mentioned in a comment here.
But I'm getting TypeError: Cannot delete property '__typename' of #<Object> if I'm trying to delete it from the response.

Not sure what is the easiest way to remove the __typename from the response but with

const responseObj = {
    ...omitDeep(JSON.parse(JSON.stringify(data)), '__typename'),
};

I could remove it from my response without the error. I think lodash.clonedeep is an alternative to JSON.parse/stringify (shallow copy) .

It's related to InMemoryCache({ freezeResult: true }) and assumeImmutableResults: true. Looks like the query results are immutable by default and it's not possible to disable the freeze of results. (related issue #5987)

So IMO the only option is to clone the object and return the mutated response.

Or what is the best practice here? Is it safe to disable the addTypename or is it recommended to keep the __typename in the JSON response?
I just wanted to have a clean JSON response without __typename but maybe it's also no problem to keep that information.

@homostellaris
Copy link

homostellaris commented Feb 23, 2022

I can see an explanation for why typename exists but no solution for it breaking mutations so I don't understand why this issue has been closed.

I agree with @luizcarlos1405 that having the server ignore the field would work. Could even take it further and have it ignore everything that begins with two underscores.

@blackge
Copy link

blackge commented Jan 4, 2023

For anyone using Typescript, you can define a Type for your mutation using the using Omit<Type, "__typename"> based on the response. This is probably simpler than some of the other solutions and means you can reuse the type wherever you need it.

Typescript Utility Types

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 14, 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