Graphql-ruby: Implement Query#sanitized_query_string

Created on 17 Nov 2017  路  8Comments  路  Source: rmosolgo/graphql-ruby

We want to improve logging, but don't leak private info into the logs. So, let's take a page out of Shopify's book (again 馃槉 ) and add a custom printer API.

Let's add a couple of steps:

  • Implement class GraphQL::Language::Printer which has print_* methods corresponding to each node type; this is the base class for custom printers.
  • Extend GraphQL::Language::Nodes::AbstractNode#to_query_string(printer: GraphQL::Language::Printer)
  • Add Schema#sanitizing_printer_class; accept options via sanitize(whitelist:, blacklist:, ... ?)
  • Add Query#sanitized_query_string which prints the document with the sanitization settings.

(I'm not sure I've got the right split of which methods go where; I'm open to reshuffling that, for sure. But I think it'd be nice to support an _injected_ printer and a base implementation for printers.)

__TODO:__ What does it look like to integrate this with Rails' parameter filtering?

If the approach works, maybe we can do something similar for https://github.com/rmosolgo/graphql-ruby/issues/791

help wanted

Most helpful comment

Just for posterity, thought I'd add this code that @rmosolgo referenced, because the GraphQL Slack only lets you see the last 10k messages:

module FilteredLanguageGeneration
  include GraphQL::Language::Generation
  extend self

  def generate(node, indent: "")
    case node
    when GraphQL::Language::Nodes::Argument
      filtered_values = FilterParameters.filtered_graphql_values(node.name => node.value)
      "#{node.name}: #{generate(filtered_values[node.name])}"
    when GraphQL::Language::Nodes::InputObject
      generate(FilterParameters.filtered_graphql_values(node.to_h))
    else
      super
    end
  end
end

All 8 comments

Working on implementing a prototype of this, will take the opportunity to refactor GraphQL::Schema::Printer and Language::Generation which implement the same logic twice in a number of places 馃憤

When I was working on our query filterer, I did wonder about moving all the string generation into each node's class. Is it still a goal to keep these separated?

Right now only AbstractNode has to_query_string, but every node type could too?

Just for posterity, thought I'd add this code that @rmosolgo referenced, because the GraphQL Slack only lets you see the last 10k messages:

module FilteredLanguageGeneration
  include GraphQL::Language::Generation
  extend self

  def generate(node, indent: "")
    case node
    when GraphQL::Language::Nodes::Argument
      filtered_values = FilterParameters.filtered_graphql_values(node.name => node.value)
      "#{node.name}: #{generate(filtered_values[node.name])}"
    when GraphQL::Language::Nodes::InputObject
      generate(FilterParameters.filtered_graphql_values(node.to_h))
    else
      super
    end
  end
end

When I was working on our query filterer, I did wonder about moving all the string generation into each node's class. Is it still a goal to keep these separated?

Right now only AbstractNode has to_query_string, but every node type could too?

Most nodes inherit from AbstractNode were the NameOnlyNodes the annoying part?

I described that terribly. I meant what about moving the string output into to_query_string for each node class instead of separated in the printer.

It would have made my filter simpler, but the new API might also accomplish that while also keeping the concerns separated.

Ah interesting!

I think the problem there is that if you wanted your custom query string produced, you'd have to inherit from the nodes themselves or have some kind of hook in there.

I can see that being tricky since the parser wouldn't generate your "custom" nodes. WDYT?

馃憣 correct that's not good. I was remembering my issues from before. In the current situation it would have been a little more direct to monkey patch a node's to_query_string instead of re-doing that generate method. But with a better printer API then that's not needed.

I posted our query printer for logging here: https://gist.github.com/rmosolgo/3452d2bf98837381df25949498e78e79 Maybe it could be upstreamed in some way.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

theodorton picture theodorton  路  3Comments

KevinColemanInc picture KevinColemanInc  路  3Comments

rmosolgo picture rmosolgo  路  4Comments

dmc2015 picture dmc2015  路  3Comments

Plummat picture Plummat  路  4Comments