最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - how to fix graphql mutations typename errors - Stack Overflow

programmeradmin6浏览0评论

I try to make a GraphQl mutation using apollo graphQl client.

This makes an error 500 when the mutation variables contains ___typename properties (which obviously don't exist in the graphQl schema).

To fix that it is possible to set addTypename: false in the graphQl client config:

const graphqlClient = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache({
    addTypename: false
  })
})

Now the mutation almost works…

But there is a new error: You're using fragments in your queries, but either don't have the addTypename: true option set in Apollo Client, or you are trying to write a fragment to the store without the __typename. Please turn on the addTypename option and include __typename when writing fragments so that Apollo Client can accurately match fragments.

So how should the graphQl client be configured to handle mutations?

for now I use a cleanup function found here:

const removeTypename = (value) => {
  if (value === null || value === undefined) {
    return value;
  } else if (Array.isArray(value)) {
    return value.map(v => removeTypename(v));
  } else if (typeof value === 'object') {
    const newObj = {};
    Object.keys(value).forEach(key => {
      if (key !== '__typename') {
        newObj[key] = removeTypename(value[key]);
      }
    });
    return newObj;
  }
  return value;
};

but it feels hacky. Is there something built-in graphql client?

I try to make a GraphQl mutation using apollo graphQl client.

This makes an error 500 when the mutation variables contains ___typename properties (which obviously don't exist in the graphQl schema).

To fix that it is possible to set addTypename: false in the graphQl client config:

const graphqlClient = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache({
    addTypename: false
  })
})

Now the mutation almost works…

But there is a new error: You're using fragments in your queries, but either don't have the addTypename: true option set in Apollo Client, or you are trying to write a fragment to the store without the __typename. Please turn on the addTypename option and include __typename when writing fragments so that Apollo Client can accurately match fragments.

So how should the graphQl client be configured to handle mutations?

for now I use a cleanup function found here:

const removeTypename = (value) => {
  if (value === null || value === undefined) {
    return value;
  } else if (Array.isArray(value)) {
    return value.map(v => removeTypename(v));
  } else if (typeof value === 'object') {
    const newObj = {};
    Object.keys(value).forEach(key => {
      if (key !== '__typename') {
        newObj[key] = removeTypename(value[key]);
      }
    });
    return newObj;
  }
  return value;
};

but it feels hacky. Is there something built-in graphql client?

Share Improve this question edited Oct 12, 2018 at 23:50 François Romain asked Oct 12, 2018 at 19:55 François RomainFrançois Romain 14.4k17 gold badges92 silver badges128 bronze badges 2
  • Are you trying to use the data returned by another query as one of your mutation's variables? Otherwise, it's not clear when the variables passed to a mutation would contain a __typename field. – Daniel Rearden Commented Oct 12, 2018 at 22:50
  • yes exactly. The ___typename were added from a previous query – François Romain Commented Oct 12, 2018 at 23:47
Add a ment  | 

2 Answers 2

Reset to default 4

So, thanks to @Daniel Rearden idea and this ment, I use a custom apollo link to strip typenames from mutations variables:

const omitTypename = (key, value) => {
  return key === '__typename' ? undefined : value
}

const omitTypenameLink = new ApolloLink((operation, forward) => {
  if (operation.variables) {
    operation.variables = JSON.parse(
      JSON.stringify(operation.variables),
      omitTypename
    )
  }
  return forward(operation)
})

Then use it with the other links like so:

const link = ApolloLink.from([authLink, omitTypenameLink, httpLink])
const cache = new InMemoryCache()

const graphqlClient = new ApolloClient({
  link,
  cache
})

Taking the value of some query and then plugging it mutation as a variable is an atypical scenario, so there's not an easy solve for what you're trying to do. While you can configure your client instance to omit the __typename field from your results, an object's __typename (along with its id or _id) are used as cache keys -- omitting it is going to cause some unexpected behavior if it doesn't outright break things.

By far the best approach to this is just to manipulate the query result before passing it in as a variable. I think something like this should do the trick:

function stripTypenames (value) {
    if (Array.isArray(value)) {
        return value.map(stripTypenames)
    } else if (value !== null && typeof(value) === "object") {
      const newObject = {}
      for (const property in value) {
          if (property !== '__typename') {
            newObject[property] = stripTypenames(value[property])
          }
      }
      return newObject
    } else {
      return value
    }
}

On a side note, unless you're using client-side data (i.e. apollo-link-state) it's hard to image a situation where you would fetch some data from the server and then have to feed that same data into a mutation. If the data exists on the server already, it should be sufficient to pass in an id for it and retrieve it server-side. If you're having to jump through these sort of hoops, it may be an indicator that the API itself needs to change.

发布评论

评论列表(0)

  1. 暂无评论