Remove Typename Link
Automatically remove __typename fields from variables.
Overview
When reusing data from a query as an argument to another GraphQL operation, __typename
fields can cause errors. To avoid this, you can use the removeTypenameFromVariables
link to automatically remove __typename
fields from variables in operations.
Remove __typename
from all variables
As an example, take the following query. Apollo Client automatically adds __typename
fields for each field selection set.
const query = gql`query DashboardQuery($id: ID!) {dashboard(id: $id) {idname}}`;const { data } = await client.query({ query, variables: { id: 1 }});// {// "dashboard": {// "__typename": "Dashboard",// "id": 1,// "name": "My Dashboard"// }// }
Now let's update this dashboard by sending a mutation to our server. We'll use the dashboard
returned from the previous query as input to our mutation.
const mutation = gql`mutation UpdateDashboardMutation($dashboard: DashboardInput!) {updateDashboard(dashboard: $dashboard) {idname}}`;await client.mutate({mutation,variables: {dashboard: { ...data.dashboard, name: 'My Updated Dashboard' }}});
Without the use of the removeTypenameFromVariables
link, the server will return an error because data.dashboard
still contains the __typename
field.
Usage
You can import and instantiate it like so:
import { removeTypenameFromVariables } from '@apollo/client/link/remove-typename';const removeTypenameLink = removeTypenameFromVariables();
Include removeTypeNameLink
anywhere in your link chain before your terminating link
to remove __typename
fields from variables for all operations.
import { from } from '@apollo/client';const link = from([removeTypenameLink, httpLink]);const client = new ApolloClient({link,// ... other options});
If you're using directional composition,
for example, to send a subscription to a websocket connection,
place removeTypenameLink
before splitLink
to remove __typename
from variables for all operations.
import { from, split } from '@apollo/client';import { removeTypenameFromVariables } from '@apollo/client/link/remove-typename';const removeTypenameLink = removeTypenameFromVariables();const splitLink = split(({ query }) => {const definition = getMainDefinition(query);return (definition.kind === 'OperationDefinition' &&definition.operation === 'subscription');},wsLink,httpLink,);const link = from([removeTypenameLink, splitLink]);const client = new ApolloClient({link,// ... other options});
Keep __typename
in JSON scalars
Sometimes, you may need to retain the __typename
field from a query's response—for example, in the case of JSON scalar input fields.
While the GraphQL type validation spec disallows input fields that begin with two underscores (__
), this restriction doesn't apply when the input field is a JSON scalar. (A JSON scalar type accepts raw JSON as input.) You can configure the removeTypenameFromVariables
link to retain __typename
for certain JSON
scalars.
To do so, provide an except
option when instantiating removeTypenameFromVariables
and use the KEEP
sentinel to denote which variables types should keep __typename
. Each key in the except
option should correspond to an input type in your GraphQL schema.
For example, suppose your schema includes a ConfigureDashboardMutation
mutation that takes a JSON
type variable named $dashboardConfig
:
mutation ConfigureDashboardMutation($dashboardConfig: JSON) {configureDashboard(config: $dashboardConfig) {id}}
You can tell the removeTypenameFromVariables
link to keep all __typename
fields for any variable declared as a JSON
type. (Variable types are inferred from the GraphQL query.)
import { removeTypenameFromVariables, KEEP } from '@apollo/client/link/remove-typename';const removeTypenameLink = removeTypenameFromVariables({except: {JSON: KEEP}});
Note: the JSON scalar type does not need to be literally named JSON
to be considered a JSON scalar.
When the query moves through the removeTypenameFromVariables
link, the dashboardConfig
variable will be detected as a JSON
scalar type and all __typename
fields are kept intact.
Nested JSON scalar fields in input variables
Not all top-level variables may map to a JSON scalar type. For more complex input object types, the JSON scalar may be found on a nested field. The except
option lets you configure nested fields within these types to keep __typename
intact.
import { removeTypenameFromVariables, KEEP } from '@apollo/client/link/remove-typename';const removeTypenameLink = removeTypenameFromVariables({except: {DashboardInput: {config: KEEP}}});
Variables declared as type DashboardInput
will have any top-level __typename
fields removed, but keep __typename
for the config
field.
This nesting can be as deep as needed and include as many fields as necessary. Use the KEEP
sentinel to determine where __typename
should be kept.
import { removeTypenameFromVariables, KEEP } from '@apollo/client/link/remove-typename';const removeTypenameLink = removeTypenameFromVariables({except: {// Keep __typename for `bar` and `baz` fields on any variable// declared as a `FooInput` typeFooInput: {bar: KEEP,baz: KEEP,},// Keep __typename for the `baz.qux` field on any variable// declared as a `BarInput` typeBarInput: {baz: {qux: KEEP}},// Keep __typename on `bar.baz` and `bar.qux.foo` fields for any// variable declared as a `BazInput` typeBazInput: {bar: {baz: KEEP,qux: {foo: KEEP}}},}});
To keep __typename
for nested fields in arrays, use the same object notation as if the field were an object type.
import { removeTypenameFromVariables, KEEP } from '@apollo/client/link/remove-typename';const removeTypenameLink = removeTypenameFromVariables({except: {// Keep __typename on the `config` field for each widget// in the `widgets` array for variables declared as// a `DashboardInput` typeDashboardInput: {widgets: {config: KEEP}}}});
Options
Name / Type | Description |
---|---|
| Determines which input types should retain |