Apollo-feature-requests: Allow deep access in filter arg in @connection directive

Created on 4 May 2019  路  8Comments  路  Source: apollographql/apollo-feature-requests

Problem

I'm currently using the @connection directive to write cache results to custom keys. However, for somewhat stupid reasons, my variables are nested like:

interface MyPayload {
  somethingRelevantInKey: String
  irrelevant: String
}

query myQuery($payload: MyPayload) {
  myQuery(payload: $payload) @connection(key: "customKey") {
    something
  }
}

MyPayload contains some data that I want to include in the cache key, and some irrelevant data.

I would like to be able to do one of the following:

query myQuery($payload: MyPayload) {
  myQuery(payload: $payload) @connection(key: "customKey", filter: ["payload.somethingRelevantInKey"]) {
    something
  }
}

query myQuery($payload: MyPayload) {
  myQuery(payload: $payload) @connection(key: "customKey", filter: [["payload", "somethingRelevantInKey"]]) {
    something
  }
}

I think this is a valid usecase, because while it may be somewhat niche to have complex variables like this, allowing this gives much finer cache control, which is an area where Apollo currently lags a bit.

Suggested Solution

In apollo-utilities/src/storeUtils.ts:210:

- filteredArgs[key] = queryArgs[key];
+ filteredArgs[key] = lodash.get(queryArgs, key)
// to support both lodash getter styles we can do filteredArgs[Array.isArray(key) ? key.join('.') : key]

We already have lodash as a dependency so nothing else needs to change.

Note that this would be a breaking change, if anyone happens to use an argument with a dot in it (which I don't think is spec compliant anyways).

Other Notes

  • Could this be a plugin?: As far as I can tell, only Apollo Server supports custom directives.
  • Is there a workaround?: Rewriting one's schema such that arguments are flat. Though I find this less readable, and a bad dev experience.
project-apollo-client

Most helpful comment

@benjamn: would you be amenable toward taking a patch for this in v2? Many of us don't have flexibility to upgrade to v3 as soon as it arrives, and it seems like there's a pretty okay workaround that would unblock many of us that use relay-style connections or nested filters.

All 8 comments

We will have something more flexible than @connection (design TBD) in the next major version of Apollo Client, and these suggestions are a good starting point!

The @connection directive was borrowed from Relay, where it was originally designed under some additional constraints (static analysis, preference for a declarative style) that could be relaxed in Apollo Client.

Great to hear! Just wondering, is there any recommendation for the current major version besides forking? Thanks!

Any update?

@leimichelle for updates, please follow the apollo-client v3 PR: https://github.com/apollographql/apollo-client/pull/5116

@benjamn: would you be amenable toward taking a patch for this in v2? Many of us don't have flexibility to upgrade to v3 as soon as it arrives, and it seems like there's a pretty okay workaround that would unblock many of us that use relay-style connections or nested filters.

To add to this: I use apollo-client v2 in conjunction with apollo-link-rest. Apollo-link-rest expects you to pass your request body parameters in a single input object. While there are ways to customise this behaviour, I couldn't get those to work with apollo:codegen (I use the generated type definitions extensively in my TypeScript app).

It seems that for now I'll be stuck using a single input object, so the suggested solution would really help me out.

For anyone wondering, in Apollo v3 this issue is solved through keyArgs.

Simply use a function like so:

keyArgs: input => input. payload.customKey // or an array if you need multiple keys

Just to make it clear

In the Apollo v3 docs keyArgs example is only for flat variables something like
const variables = { id: string, sortBy: string}
and it will be like

  Query: {
    fields: {
       getItems: {
          merge: (existing, incoming) { ... },
          keyArgs: ["sortBy"] //  if we want different set of data for different value of sortBy 
       }
    }
  } 
 ```

 but what if we have nested variables like

const variables = {
payload : {
id: string
sortBy: string
}
}

In keyArgs it will be

Query: {
fields: {
getItems: {
merge: (existing, incoming) { ... },
keyArgs: ["payload", ["sortBy"]] // I hope you get the pattern ["payload", ["sortBy", "you can add more child of payload"]]
}
}
}
```

Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jbachhardie picture jbachhardie  路  3Comments

Vincz picture Vincz  路  3Comments

LennardWesterveld picture LennardWesterveld  路  7Comments

haizz picture haizz  路  3Comments

aldofunes picture aldofunes  路  6Comments