pavelmickevic
pavelmickevic

Reputation: 11

@include or @skip directives applied in post-resolver, not pre-resolver. Eventually hitting the backend instead of omitting a property on a client

Consider the example:

query myListQuery($someTest: Boolean) {
  id
  price
  taxRate
  expensiveField @skip(if: $someTest)
}

here, the graphQL query will be executed; in its server resolvers, GQL operation body will be translated to an appropriate REST request, e.g. POST /list. REST API responds with an array of full entities, e.g.:

[
  { id, product, color, size, price, taxRate, expensiveField }, 
  { id, product, color, size, price, taxRate, expensiveField }, 
  { id, product, color, size, price, taxRate, expensiveField }, 
]

Mind, the expensiveField; it is expensive, because it is computed in the runtime of a backend, on-request. (Even though its Math.multiply(price, taxRate)).

Now that the GQL server received the response from REST, it starts applying some filtering of properties: firstly it returns me fields that I requested originally (id, price, taxRate only), but secondly it applies the directive of @skip (here, for expensiveField). The filtering is happening in post-processing! This is bad, IMO.


I tried to fine-tune the POST /list endpoint, that would accept the ?fields= argument. That way I can whitelist the exact fields that I request from the GraphQL. Easy. But I, eventually, realized, that the Apollo Client and Apollo Server anyway sends me those properties to REST, even if they are under the directive of @skip. As directive is applied for post-processing.

As a workaround, I need to implement a custom logic on the fronted now, to strip out the fields marked with a directive.

query myListQuery($someTest: Boolean) {
  id
  price
  taxRate
  -expensiveField @skip(if: $someTest)
  +#expensiveField @skip(if: $someTest)
}

Is there any library that works in pair with import gql from 'graphql-tag';/gql`` and can strip out the directives automatically for me, on the client-side?

Upvotes: 1

Views: 285

Answers (1)

pavelmickevic
pavelmickevic

Reputation: 11

After searching for some time online, I came to this Apollo Link (read more about Links concept) @freshcells/apollo-link-field-keep

This is exactly what I was looking for. Let me give an example:

This is how you write the code in the source

query myListQuery {
  id
  price
  taxRate
  expensiveField @keep(if: false)
}

eventually directive does strip out the expensiveField field away on a Client side, producing such request body:

query myListQuery {
  id
  price
  taxRate
}

It also works perfectly with subfields.

query myQuery {
  post(id: 123) {
    id
    name
    author @keep(if: false) {
      firstName
      lastName
    }
  }
}

will strip out the author {} completely on the Client side, resulting in:

query myQuery {
  post(id: 123) {
    id
    name
  }
}

Plus, cherry on top, it will remove the whole field query including arguments. It will also clean up all variables that might be used (if not used by other fields).

P.S. There are also use cases for feature-flagging

Upvotes: 0

Related Questions