2

Good sirs. How can I force the request.body (or any other non-JSON string) to print out in a nice multi-lined JSON or yaml style?

I have seen fancy methods to convert such strings to real JSON but was hoping to avoid putting in another method.

  def request_token_from_google
    uri = URI.parse('https://www.googleapis.com/oauth2/v3/token')
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    request = Net::HTTP::Post.new(uri.request_uri)
    request.set_form_data(self.to_params)
    puts "request body is"
    puts request.body.to_yaml # doesn't work
    puts request.body.to_json # doesn't work
    http.request(request)
  end
dwilbank
  • 2,470
  • 2
  • 26
  • 37
  • `request.body` is just a form-encoded string, like `foo=1&bar=2&...`. Can you edit your question to give us an example of what you'd like the output to look like? – Jordan Running Jun 03 '15 at 22:18
  • Thanks. Reshaped the question based upon this new insight. – dwilbank Jun 03 '15 at 22:36
  • I'm not really clear on what you're doing, but I suggest you install [pry rails](https://github.com/rweng/pry-rails) and see if it doesn't solve your problem. It's kind of a shot-in-the dark suggestion, but pry rails is my go-to tool for just about everything anyway. – crowhill Jun 03 '15 at 22:45
  • Good shot, but pry still prints the request.body string as a long single-line string, instead of as an object. – dwilbank Jun 03 '15 at 22:58
  • It's not clear to me why you don't just inspect `self.to_params`, since that's the data you're putting into the request. If you decode the form data you're just going to get the same data back out again. – Jordan Running Jun 03 '15 at 23:09
  • True. I just wanted to visualize the entire request.body string so I could see how the params all fit in there. – dwilbank Jun 04 '15 at 01:43

1 Answers1

2

The problem with this:

ap "request body is #{request.body.to_json}"

...and your other attempts is that you're trying to pretty-print something that's already a string. The purpose of awesome_print (and inspect and their ilk) is to take an object that has some structure and print it such that you can see its structure, but a string has no structure—it's just character, character, character. When you give awesome_print a string like "request body is {"foo":... it has no way of knowing that there's anything special about the part after "is."

If you had an object with structure, the solution would be to give it directly to awesome_print:

puts "request body is:"
ap my_hash_or_array

Unfortunately, in this case it's not going to help, because request.body is just a string, too—it's form-encoded data, like this (stolen from Wikipedia):

Name=Jonathan+Doe&Age=23&Formula=a+%2B+b+%3D%3D+13%25%21

Just like the "request body is..." example, awesome_print has no way of knowing that this is anything special. One really simple thing you could do is just put a newline between each key/value pair:

body = "Name=Jonathan+Doe&Age=23&Formula=a+%2B+b+%3D%3D+13%25%21"

puts "Request body is:"
puts body.gsub("&", "\n  &")
# => Request body is:
#    Name=Jonathan+Doe
#      &Age=23
#      &Formula=a+%2B+b+%3D%3D+13%25%21

This has the downside that the values are still percent-encoded, as you can see in the case of Formula. If that's a problem you can parse the form data using CGI.parse or Rack::Utils.parse_query, both of which are available in Rails. They both return a Hash that you can give to awesome_print, but slightly different formats (CGI returns all values as Arrays, Rack::Utils only does if they're in "array" format, e.g. foo[]=1&foo[]=2). Here's Rack::Utils (you'll just have to imagine that the output is colored):

puts "Request body is:"
ap Rack::Utils.parse_query(body)
# => Request body is:"
#    {
#           "Name" => "Jonathan Doe",
#            "Age" => "23",
#        "Formula" => "a + b == 13%!"
#    }

Finally, a little unsolicited advice: puts and ap, which write to STDOUT, tend to work fine in development because Rails' logger is also writing to STDOUT, so you see the puts output in the same terminal window as the Rails server log. In production, however, data written to STDOUT might not be written to a file anywhere, and even if it is, if you change the Rails.logger configuration at some point, ap's output may still be going somewhere else. What you probably want is to use Rails' logger instead of puts or ap, so you can be sure that all of your output goes to the same place. Fortunately, awesome_print adds an awesome_inspect method to every object, which returns the same pretty string you see when you use ap, so you can still use awesome_print with Rails.logger:

body_inspect = Rack::Utils.parse_query(body).awesome_inspect
Rails.logger.info("Request body is:\n#{body_inspect}")
Jordan Running
  • 102,619
  • 17
  • 182
  • 182