20

I use 'gem json' and need load JSON data from some url, for example:

"http://locallhost:3000/qwerty/give_json.json" with

{"one":"Omg","two":125,"three":"Hu"}

I have rails app

class QwertyController < ApplicationController
    require 'json'

    def get_json
        source = "http://localhost:3000/qwerty/give_json.json"
        @data = JSON.parse(JSON.load(source))
    end
end

I get error

JSON::ParserError in QwertyController#get_json
795: unexpected token at 'http://localhost:3000/qwerty/give_json.json'

In string: @data = JSON.parse(JSON.load(source))

What is the matter? How can I get JSON data and parse it? I try @data["one"] ...

5
  • Looks like you have invalid JSON in the source Commented Sep 2, 2013 at 22:55
  • No it's not. I created a rails app, which generate JSON answer on port 3000 (localhost:3000/qwerty/give_json.json). And second app, which try to get JSON data on port 3001 (localhost:3001/qwerty/get_json) Commented Sep 2, 2013 at 22:59
  • 2
    What version of ruby are you using? you don't need to require json in newer versions of rails and ruby... Commented Sep 2, 2013 at 23:00
  • alexkd@Active-pc:~$ ruby -v ruby 1.9.3p448 (2013-06-27 revision 41675) [i686-linux] alexkd@Active-pc:~$ rails -v Rails 4.0.0 Commented Sep 2, 2013 at 23:03
  • Yes you do have invalid JSON. YOu are calling JSON.load on a URL string, not a JSON object. That is invalid JSON. JSON.load doesnt read data from a url, you are just passing the string in Commented Sep 2, 2013 at 23:10

4 Answers 4

53

JSON.load takes a source that is a String or IO object according to the documentation

http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html#method-i-load

[17] pry(main)> {hello: "World"}.to_json
=> "{\"hello\":\"World\"}"
[18] pry(main)> JSON.load(_)
=> {"hello"=>"World"}

You're giving it a String that is a URL and that's why you're getting an error. You can use open-uri to fetch the data from the URL to then be parsed by JSON like so...

[22] pry(main)> require 'open-uri'
=> false
[23] pry(main)> JSON.load(URI.open("https://api.github.com"))
=> {"current_user_url"=>"https://api.github.com/user",
 "authorizations_url"=>"https://api.github.com/authorizations",
 "emails_url"=>"https://api.github.com/user/emails",
 "emojis_url"=>"https://api.github.com/emojis",
 "events_url"=>"https://api.github.com/events",
 "feeds_url"=>"https://api.github.com/feeds",
 "following_url"=>"https://api.github.com/user/following{/target}",
 "gists_url"=>"https://api.github.com/gists{/gist_id}",
 "hub_url"=>"https://api.github.com/hub"}

NOTE

URI.open returns a StringIO object which responds to read returning the JSON data. JSON.load turns the data into a hash to be used.

To parse the JSON string you can either use JSON.load or JSON.parse

Sign up to request clarification or add additional context in comments.

3 Comments

that is a really good solution!! I had to explicitly call URI.open, otherwise it gave me a No such file or directory error, but other then that, I found this to be the most elegant solution.
@wnm same for me. If it's like that for everyone we should probably edit the answer to include it. I have no idea if it's the way for everyone
It's likely that the open call may have worked in the past but now it's invoking Kernel#call which would return the error you're seeing now. I've updated the solution to include URI as part of the call
18

You could use net/http library like below:

   require 'net/http'
   source = 'http://localhost:3000/qwerty/give_json.json'
   resp = Net::HTTP.get_response(URI.parse(source))
   data = resp.body
   result = JSON.parse(data)

Or the gem http party:

require 'httparty'

response = HTTParty.get('http://localhost:3000/qwerty/give_json.json')
json = JSON.parse(response.body)

Comments

3

By default, httparty already includes the JSON library within httparty.rb.
This means that the call to require 'json' is unnecessary.

Thanks for providing these examples!

Comments

3

You could use JSON and net/http lib.. which is below:

require 'net/http'
require 'json'

url = "https://api.url/"
uri = URI(url)
response = Net::HTTP.get(uri)
data = JSON.parse(response)
objs.each do |data|
  title = data["title"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.