Read JSON formatted response from Google finance api - ruby-on-rails

The code for get data from google-finance url:
uri =URI.parse('http://finance.google.com/finance/info?client=i&q=NSE:ANDHRABANK')
rs = Net::HTTP.get(uri)
rs.delete! '//'
a = JSON.parse(rs)
p a
This is the response:
[{"id"=>"15355585", "t"=>"ANDHRABANK", "e"=>"NSE", "l"=>"49.30", "l_fix"=>"49.30", "l_cur"=>"₹49.30", "s"=>"0", "ltt"=>"3:30PM GMT+5:30", "lt"=>"Jan 13, 3:30PM GMT+5:30", "lt_dts"=>"2017-01-13T15:30:00Z", "c"=>"-0.15", "c_fix"=>"-0.15", "cp"=>"-0.30", "cp_fix"=>"-0.30", "ccol"=>"chr", "pcls_fix"=>"49.45"}]
Unable to access the JSON array. Want to access the array in a['t'] manner.

Since you're dealing with a hash in an array, you have to specify the array element position as well:
require 'json'
require 'net/http'
uri = URI.parse('http://finance.google.com/finance/info?client=i&q=NSE:ANDHRABANK')
rs = Net::HTTP.get(uri)
rs.delete! '//'
a = JSON.parse(rs)
p a.class #=> Array
p a[0]["t"] #=> "ANDHRABANK"

Either you run loop on array then you can access using a[i]["t"] or use a[0]["t"].
Note: i is the index of array elements.

You aren't making it easy for yourself. Consider this:
require 'json'
require 'open-uri'
rs = open('http://finance.google.com/finance/info?client=i&q=NSE:ANDHRABANK').read
foo = JSON[rs[4..-1]].first
foo['t'] # => "ANDHRABANK"
Rather than deal with the intricacies of Net::HTTP, which is more useful as a tool to build new HTTP services, I'd recommend relying on OpenURI, or one of the many HTTP clients available. The advantage over Net::HTTP is redirection is automatically handled plus simplicity. OpenURI does have some downsides, but for a basic URL getter it's fine.
The JSON class has [] which is smart enough to convert a string into the corresponding Ruby object. It'll also serialize a Ruby object back into a String:
puts JSON[{'a' => 1}]
# >> {"a":1}
The service you're calling is returning JSON, only, in this case, it's a single-element array containing a hash. Using first makes it easy to retrieve the hash and access it normally. It's cleaner to do that than to sprinkle your code with this form:
foo[0]['t']
which is longer to type and results in a visual noise.

Related

How to check for successful response from API in rails by just using status code?

I am consuming an API using a gem in Ruby on Rails. The gem makes the API call for me and returns the status code as an integer (for example 200, 201 e.t.c.) and the data response from the API.
def get_cars
status_code, data = MyGem::Cars.get_cars
if status_code in SUCCESSFUL_RESPONSE_CODES
# Perform data manipulation
else
raise "There was an error processing the request. Status code #{status_code}"
end
end
Now I have manually initialised SUCCESSFUL_RESPONSE_CODES as a list containing integers of successful codes I found here.
Is this list defined somewhere in Ruby/RoR to avoid manually defining it?
I would expect any widely supported gem to use standard HTTP response codes to determine if the HTTP response was a success. For example:
require 'open-uri' # Rails loads this by default.
res = open('http://example.com')
res.status
=> ["200","OK"]
status.include?'OK'
=>true
status.include?'200'
=> true
So long as you trust the gem code making your request to handle standard HTTP response codes, you should be ok. Here's another example using HTTParty gem
require 'HTTParty'
res = HTTParty.get('https://example.com')
res.success?
=> true

Swapping Rails 4 ParamsParser removes params body

I'm trying to follow this solution to add a params parser to my rails app, but all that happens is that I now get the headers but no parameters from the body of the JSON request at all. In other words, calling params from within the controller returns this:
{"controller"=>"residences", "action"=>"create",
"user_email"=>"wjdhamilton#wibble.com",
"user_token"=>"ayAJ8kDUKjCiy1r1Mxzp"}
but I expect this as well:
{"data"=>{"type"=>"residences",
"attributes"=>{"name-number"=>"The Byre",
"street"=>"Next Door",
"town"=>"Just Dulnain Bridge",
"postcode"=>"PH1 3SY",
"country-code"=>""},
"relationships"=>{"residence-histories"=>{"data"=>nil},
"occupants"=>{"data"=>nil}}}}
Here is my initializer, which as you can see is almost identical to the one in the other post:
Rails.application.config.middleware.swap(
::ActionDispatch::ParamsParser, ::ActionDispatch::ParamsParser,
::Mime::Type.lookup("application/vnd.api+json") => Proc.new { |raw_post|
# Borrowed from action_dispatch/middleware/params_parser.rb except for
# data.deep_transform_keys!(&:underscore) :
data = ::ActiveSupport::JSON.decode(raw_post)
data = {:_json => data} unless data.is_a?(::Hash)
data = ::ActionDispatch::Request::Utils.deep_munge(data)
# Transform dash-case param keys to snake_case:
data = data.deep_transform_keys(&:underscore)
data.with_indifferent_access
}
)
Can anyone tell me where I'm going wrong? I'm running Rails 4.2.7.1
Update 1: I decided to try and use the Rails 5 solution instead, the upgrade was overdue anyway, and now things have changed slightly. Given the following request:
"user_email=mogwai%40balnaan.com
&user_token=_1o3Kpzo4gTdPC2bivy
&format=json
&data[type]=messages&data[attributes][sent-on]=2014-01-15
&data[attributes][details]=Beautiful+Shetland+Pony
&data[attributes][message-type]=card
&data[relationships][occasion][data][type]=occasions
&data[relationships][occasion][data][id]=5743
&data[relationships][person][data][type]=people
&data[relationships][person][data][id]=66475"
the ParamsParser middleware only receives the following hash:
"{user":{"email":"mogwai#balnaan.com","password":"0h!Mr5M0g5"}}
Whereas I would expect it to receive the following:
{"user_email"=>"mogwai#balnaan.com", "user_token"=>"_1o3Kpzo4gTdPC2b-ivy", "format"=>"5743", "data"=>{"type"=>"messages", "attributes"=>{"sent-on"=>"2014-01-15", "details"=>"Beautiful Shetland Pony", "message-type"=>"card"}, "relationships"=>{"occasion"=>{"data"=> "type"=>"occasions", "id"=>"5743"}}, "person"=>{"data"=>{"type"=>"people", "id"=>"66475"}}}}, "controller"=>"messages", "action"=>"create"}
The problem was caused by the tests that I had written. I had not added the Content-Type to the requests in the tests, and had not explicitly converted the payload to JSON like so (in Rails 5):
post thing_path, params: my_data.to_json, headers: { "Content-Type" => "application/vnd.api+json }
The effects of this were twofold: Firstly, since params parsers are mapped to specific media types then withholding the media type meant that rails assumed its default media type (in this case application/json) so the parser was not used to process the body of the request. What confused me was that it still passed the headers to the parser. Once I fixed that problem, I was then faced with the body in the format of the request above. That is where the explicit conversion to JSON is required. I could have avoided all of this if I had just written accurate tests!

743: unexpected token at '... in Ruby on Rails

I saved a file named array.json on my Dropbox folder and i access to it via Dropbox API. All works fine, but when i retrieve JSON content i cannot JSON.parse that string!!
session = DropboxSession.new(APP_KEY, APP_SECRET)
session.set_access_token(ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET)
client = DropboxClient.new(session, ACCESS_TYPE)
json = client.get_file(DIRECTORY + '/array.json')
#json = JSON.parse json
Error:
743: unexpected token at '{"Nome" : "Mario Rossi",
"C.F." : "ABCDEFGHILMNOP",
"Booking Assistance" : "MARIO",
"Status of reservation" : "25/11/2011"}'
JSON string is valid!! if i copy this string and paste it (manually) as parameter in JSON.parse(), json is parsed correctly!! So i think is a encoding problem...but where i wrong?
We have abandoned the json parsing backend that is the default in Rails. The default backend is YAML based and imo a useless mess. After several gotchas parsing unicode, and dates in some cases, we discovered that the backend can be replaced via configuration.
You can substitute the parsing backend in an initializer
ActiveSupport::JSON.backend = "JSONGem"
There are several gems that can be used as the backend, we just use the json gem
gem 'json'

Trouble handling HTTP responses and parsing JSON data

I am using Ruby on Rails 3 and I would like to solve an issue with the following code where a web client application receive back some JSON data from a web service application that uses a Rack middleware in order to respond.
In the web client app model I have
response_parsed = JSON.parse(response.body)
if response_parsed["account"]
...
else
return response
end
In the above code the response.body come back from the web service app that uses a Rack middleware to respond to the web client:
accounts = Account.where(:id => ids)
[200, {'Content-Type' => 'application/json'}, accounts.to_json] # That is, response.body = accounts.to_json
Data transmission is ok, but I get the following error
TypeError
can't convert String into Integer
*Application Trace*
lib/accounts.rb:107:in `[]'
The line 107 corresponds to
if response_parsed["account"]
...
Where and what is the problem? How to solve that?
If I try to debug the respons.body I get
# Note: this is an array!
"[{\"account\":{\"firstname\":\"Semio\",\"lastname\":\"Iaven\"\"}}]"
If I'm saying something you already realize, forgive me.
It looks like your response is a one-element array with a hash in it as the first element. Because the response is an array, when you use the [] it is expecting a integer representing the index of the item in the array you'd like to access, and that is what the error message means--it expected that you'd tell it the integer value of the item you wanted, but instead you gave it a string.
If you instead do:
response_parsed[0]['account']
It seems like you'd get what you want.

Ruby SQS Parsing Message?

Initially I sent the converted object using .to_json which gives me a string I sent this to sqs. Now i'm retrieving the message and now it's in string form? How do I parse it back into my inital object?
--Edit
Ruby on Rails. I'm using a library to contact sqs and send the object over. Before I send it, I convert it using .to_json. Then Now, I'm writing a backend.rb file that uses that library and receives the msg and if there is a msg i want it to convert that msg back into a #project then I plan to send this #project over to a template .erb file.
To turn a JSON string into Ruby objects, call JSON.parse like so:
require 'json'
JSON.parse( '{"foo":"bar"}' )
#=> {"foo"=>"bar"}
a = JSON.parse( '[1,2,3] )
#=> [1, 2, 3]
JSON.parse( '{"name":"Gavin","cats":["Phleep","Tessa"]}' )
#=> {"name"=>"Gavin", "cats"=>["Phleep", "Tessa"]}

Resources