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:
class GraphQL::Language::Printer which has print_* methods corresponding to each node type; this is the base class for custom printers. GraphQL::Language::Nodes::AbstractNode#to_query_string(printer: GraphQL::Language::Printer)Schema#sanitizing_printer_class; accept options via sanitize(whitelist:, blacklist:, ... ?)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
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.
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: