Jim Wu
Jim Wu

Reputation: 149

Ruby, Parsing a JSON response for an array of values

I'm new to ruby so please excuse any ignorance I may bear. I was wondering how to parse a JSON reponse for every value belonging to a specific key. The response is in the format,

[
  {
    "id": 10008,
    "name": "vpop-fms-inventory-ws-client",
    "msr": [
      {
        "key": "blocker_violations",
        "val": 0,
        "frmt_val": "0"
      },
    ]
  },
  {
    "id": 10422,
    "name": "websample Maven Webapp",
    "msr": [
      {
        "key": "blocker_violations",
        "val": 0,
        "frmt_val": "0"
      }...

There's some other entries in the response, but for the sake of not having a huge block of code, I've shortened it.The code I've written is:

require 'uri'
require 'net/http'
require 'JSON'
url = URI({my url})

    http = Net::HTTP.new(url.host, url.port)

    request = Net::HTTP::Get.new(url)
    request["cache-control"] = 'no-cache'
    request["postman-token"] = '69430784-307c-ea1f-a488-a96cdc39e504'

    response = http.request(request)
    parsed = response.read_body

    h = JSON.parse(parsed)

    num = h["msr"].find {|h1| h1['key']=='blocker_violations'}['val']

I am essentially looking for the val for each blocker violation (the json reponse contains hundreds of entries, so im expecting hundreds of blocker values). I had hoped num would contain an array of all the 'val's. If you have any insight in this, it would be of great help!

EDIT! I'm getting a console output of

scheduler caught exception:
no implicit conversion of String into Integer
C:/dashing/test_board/jobs/issue_types.rb:20:in `[]'
C:/dashing/test_board/jobs/issue_types.rb:20:in `block (2 levels) in <top (requi
red)>'
C:/dashing/test_board/jobs/issue_types.rb:20:in `select'

I suspect that might have too much to do with the question, but some help is appreciated!

Upvotes: 0

Views: 2663

Answers (1)

MrWillihog
MrWillihog

Reputation: 2646

You need to do 2 things. Firstly, you're being returned an array and you're only interested in a subset of the elements. This is a common pattern that is solved by a filter, or select in Ruby. Secondly, the condition by which you wish to select these elements also depends on the values of another array, which you need to filter using a different technique. You could attempt it like this:

res = [
  {
    "id": 10008,
    "name": "vpop-fms-inventory-ws-client",
    "msr": [
      {
        "key": "blocker_violations",
        "val": 123,
        "frmt_val": "0"
      }
    ]
  },
  {
    "id": 10008,
    "name": "vpop-fms-inventory-ws-client",
    "msr": [
      {
        "key": "safe",
        "val": 0,
        "frmt_val": "0"
      }
    ]
  }
]

# define a lambda function that we will use later on to filter out the blocker violations
violation = -> (h) { h[:key] == 'blocker_violations' }

# Select only those objects who contain any msr with a key of     blocker_violations
violations = res.select {|h1| h1[:msr].any? &violation }

# Which msr value should we take? Here I just take the first.
values = violations.map {|v| v[:msr].first[:val] }

The problem you may have with this code is that msr is an array. So theoretically, you could end up with 2 objects in msr, one that is a blocker violation and one that is not. You have to decide how you handle that. In my example, I include it if it has a single blocker violation through the use of any?. However, you may wish to only include them if all msr objects are blocker violations. You can do this via the all? method.

The second problem you then face is, which value to return? If there are multiple blocker violations in the msr object, which value do you choose? I just took the first one - but this might not work for you.

Depending on your requirements, my example might work or you might need to adapt it.

Also, if you've never come across the lambda syntax before, you can read more about it here

Upvotes: 1

Related Questions