Class: GraphQL::Language::SanitizedPrinter

Inherits:
Printer
  • Object
show all
Defined in:
lib/graphql/language/sanitized_printer.rb

Overview

A custom printer used to print sanitized queries. It inlines provided variables within the query for facilitate logging and analysis of queries.

The printer returns nil if the query is invalid.

Since the GraphQL Ruby AST for a GraphQL query doesnt contain any reference on the type of fields or arguments, we have to track the current object, field and input type while printing the query.

Examples:

Printing a scrubbed string

printer = QueryPrinter.new(query)
puts printer.sanitized_query_string

See Also:

  • {Query{Query#sanitized_query_string}

Constant Summary collapse

REDACTED =
"\"<REDACTED>\""

Instance Method Summary collapse

Methods inherited from Printer

#print

Constructor Details

#initialize(query) ⇒ SanitizedPrinter

Returns a new instance of SanitizedPrinter.


22
23
24
25
26
27
# File 'lib/graphql/language/sanitized_printer.rb', line 22

def initialize(query)
  @query = query
  @current_type = nil
  @current_field = nil
  @current_input_type = nil
end

Instance Method Details


62
63
64
65
66
67
68
69
70
71
# File 'lib/graphql/language/sanitized_printer.rb', line 62

def print_argument(argument)
  arg_owner = @current_input_type || @current_directive || @current_field
  arg_def = arg_owner.arguments[argument.name]

  old_input_type = @current_input_type
  @current_input_type = arg_def.type.non_null? ? arg_def.type.of_type : arg_def.type
  res = super
  @current_input_type = old_input_type
  res
end

120
121
122
123
124
125
126
127
# File 'lib/graphql/language/sanitized_printer.rb', line 120

def print_directive(directive)
  @current_directive = query.schema.directives[directive.name]

  res = super

  @current_directive = nil
  res
end

86
87
88
89
90
91
92
93
# File 'lib/graphql/language/sanitized_printer.rb', line 86

def print_field(field, indent: "")
  @current_field = query.schema.get_field(@current_type, field.name)
  old_type = @current_type
  @current_type = @current_field.type.unwrap
  res = super
  @current_type = old_type
  res
end

109
110
111
112
113
114
115
116
117
118
# File 'lib/graphql/language/sanitized_printer.rb', line 109

def print_fragment_definition(fragment_def, indent: "")
  old_type = @current_type
  @current_type = query.schema.types[fragment_def.type.name]

  res = super

  @current_type = old_type

  res
end

95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/graphql/language/sanitized_printer.rb', line 95

def print_inline_fragment(inline_fragment, indent: "")
  old_type = @current_type

  if inline_fragment.type
    @current_type = query.schema.types[inline_fragment.type.name]
  end

  res = super

  @current_type = old_type

  res
end

73
74
75
76
77
78
79
# File 'lib/graphql/language/sanitized_printer.rb', line 73

def print_list_type(list_type)
  old_input_type = @current_input_type
  @current_input_type = old_input_type.of_type
  res = super
  @current_input_type = old_input_type
  res
end

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/graphql/language/sanitized_printer.rb', line 38

def print_node(node, indent: "")
  if node.is_a?(String)
    type = @current_input_type.unwrap
    # Replace any strings that aren't IDs or Enum values with REDACTED
    if type.kind.enum? || type.graphql_name == "ID"
      super
    else
      REDACTED
    end
  elsif node.is_a?(Array)
    old_input_type = @current_input_type
    if @current_input_type && @current_input_type.list?
      @current_input_type = @current_input_type.of_type
      @current_input_type = @current_input_type.of_type if @current_input_type.non_null?
    end

    res = super
    @current_input_type = old_input_type
    res
  else
    super
  end
end

Print the operation definition but do not include the variable definitions since we will inline them within the query


131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/graphql/language/sanitized_printer.rb', line 131

def print_operation_definition(operation_definition, indent: "")
  old_type = @current_type
  @current_type = query.schema.public_send(operation_definition.operation_type)

  out = "#{indent}#{operation_definition.operation_type}".dup
  out << " #{operation_definition.name}" if operation_definition.name
  out << print_directives(operation_definition.directives)
  out << print_selections(operation_definition.selections, indent: indent)

  @current_type = old_type
  out
end

81
82
83
84
# File 'lib/graphql/language/sanitized_printer.rb', line 81

def print_variable_identifier(variable_id)
  variable_value = query.variables[variable_id.name]
  print_node(value_to_ast(variable_value, @current_input_type))
end

#sanitized_query_stringString?

Returns A scrubbed query string, if the query was valid.

Returns:

  • (String, nil)

    A scrubbed query string, if the query was valid.


30
31
32
33
34
35
36
# File 'lib/graphql/language/sanitized_printer.rb', line 30

def sanitized_query_string
  if query.valid?
    print(query.document)
  else
    nil
  end
end