Skip to content

Cache Key Deconfliction #470

@dyst5422

Description

@dyst5422

We have a client that utilizes multiple APIs published by different teams in our org. We already support routing our queries to different APIs based on a directive.

query listTypeA($input: ListTypeAInput!) @api(name: API_A) {
  listTypeA(input: $input) {
    id
    someOtherField
  }
}

And a routing link

const apiRoutingLink =  new ApolloLink((operation, forward) => {
  const apiName = findDirectiveValue(operation.query, 'api', 'name');
  operation.setContext({
    ...operation.getContext(),
    apiName: api,
  });
  return forward(operation);
});

const httpLink = new HttpLink({
  uri: ({ getContext }) => {
    const { apiName } = getContext() as { apiName: DataProductApi };
    return apiEndpointConfig[apiName];
  },
  headers: {
    Authorization: `Bearer ${midwayToken}`,
  },
});

This works great, except that we have similar type names in the two APIs due to the shared domain (TypeA).

What I'd like it be able to deconflict our cache entries by prepending the api name to our cache key. Unfortunately, the tooling available is insufficient. The only way to do so for all types without exhaustively creating type policies is with dataIdFromObject, but that doesn't allow deep id specification. Specifically, we have a type Dataflow whose unique identifier is a combination of sub properties. We can do this with typePolicies like

Dataflow: {
  keyFields: ['dataflowId', 'destination', ['config', ['id']], 'source', ['config', ['id']]],
},

but these descendants are not available in dataIdFromObject, which just has refs in their place.

What I'd like to be able to do is a dataIdFromObject function that has access throughout the descendants like so

dataIfFromObject(responseObject) {
  const api = (responseObject as typeof responseObject & { [APPENDED_SYMBOL]?: string })[APPENDED_SYMBOL];
  case 'Dataflow': {
    return `${api}:${responseObject.__typename}:${responseObject.dataflow}:${responseObject.destination.config.id}:${responseObject.source.config.id}`;
  default:
    return `${api}:${responseObject.__typename}`;
}

Alternative approaches would be a post processing function for the type policies, or a default type policy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions