I have a backend to an IOS application. I am trying to read the data from my rails backend by using JSON. My bubbleWrap get request is as follows.
BW::HTTP.get("url_here/children/1.json") do |response|
json = BW::JSON.parse response.body.to_str
for line in json
p line[:name]
end
end
It doesn't bring any data back, it actually breaks my code. I can't find any documentation with an example of how to use REST from rubymotion/Bubblewrap and pull data back to my application.
Any help is appreciated.
Here's a handy class abstraction that I use in a lot of my applications... it completely abstracts the API call logic from the view controller logic for separation of concerns and is heavily modeled after Matt Green's Inspect 2013 talk.
class MyAPI
APIURL = "http://your.api.com/whatever.json?date="
def self.dataForDate(date, &block)
BW::HTTP.get(APIURL + date) do |response|
json = nil
error = nil
if response.ok?
json = BW::JSON.parse(response.body.to_str)
else
error = response.error_message
end
block.call json, error
end
end
end
Then to call this class we do:
MyAPI.dataForDate(dateString) do |json, error|
if error.nil?
if json.count > 0
json.each do |cd|
# Whatever with the data
end
else
App.alert("No Results.")
end
else
App.alert("There was an error downloading data from the server. Please check your internet connection or try again later.")
end
end
Always check the response code before parsing the response body. You might
BW::HTTP.get(url) do |response|
if response.ok?
data = BW::JSON.parse(response.body.to_str)
# make sure you have an array or hash before you try iterating over it
data.each {|item| p item}
else
warn "Trouble"
end
end
Also make sure you sanity-check the JSON response vs your code's expectation. Perhaps the JSON is an array and not a hash?
Related
I am learning Elixir and Phoenix, I'm building a side project that needs to query Github's APIs.
This is the module that performs the call
defmodule Github do
use HTTPoison.Base
def process_url(url) do
"https://api.github.com/" <> url
end
def process_response_body(body) do
body
|> Poison.decode!
|> Enum.map(fn({k, v}) -> {String.to_atom(k), v} end)
end
end
and this is the Controller that answers to a GET on "/api/github/search"
defmodule MyApp.GithubController do
use MyApp.Web, :controller
require Github
def search(conn, _params) do
json conn, search_repositories
end
def search_repositories() do
url = "search/repositories?q=language:javascript&sort=stars&order=desc"
Github.get! url
end
end
I get an error page from Phoenix which says at the top
unable to encode value: {:total_count, 2389278}
So something is working, I am actually calling Github's API, but for some reason I'm missing a step, I've followed the example here https://github.com/edgurgel/httpoison#wrapping-httpoisonbase
Any help / hint is highly appreciated!
Not sure what your expected result is, but I assume you just want to return from your controller the complete response from Github as JSON. Just let Poison handle the decoding, no need to process it further.
def process_response_body(body) do
body
|> Poison.decode!
end
Your missing piece is the fact that get! doesn't return the JSON, but a %HTTPoison.Response struct as can be seen in the first usage example here https://github.com/edgurgel/httpoison
The struct contains your processed body, headers and the status code. You can use pattern matching to extract your json and return it:
def search_repositories() do
url = "search/repositories?q=language:javascript&sort=stars&order=desc"
%HTTPoison.Response{:body => json, :headers => headers, :status_code => code} = Github.get! url
IO.inspect headers
IO.inspect code
json
end
I ma new to writing python unit tests. I have a method in a class returning a Json response from an API. The JSON response contains attributes such as data, token, object name and status. The method hits API and returns response with different values each time, so I can't hard code a response and test it. How can I write a unit test for this type of method.
One thing, I thought of is to check whether the response is not null. Is there any other type of checks I can do here.
Each time it returns a different token, date(timestamp). The status will be same.
def Json_get_status(self):
get_url = "xxxx" #URL to hit API
r = requests.get(get_url)
self.get_json = json.loads(r.text)
self.get_token=self.get_json["token"]
self.get_date=self.get_json["date"]
self.get_status=self.get_json["status"]
return self.get_json
If your method under test is supposed to "read the status correctly", then you might want to specifically test that.
So assuming your app is something like
def read_status(response):
parsed = json.loads(response)
# does other stuff
return something
Then in your test_unit.py
def test_read_status(self):
mock_input_val = {'something': 'good val'}
expected_positive_return_val = something
self.assertEqual(read_status(json.dumps(mock_input_val)),
expected_positive_return_val)
Also good to do a negative test for the condition where read_status either fails to parse the json object or finds an error in the response.
I am trying to get list of wall post from Vk.com using Vontakte, mongoengine, Django
Here is my view, where wallposts = vk.get('wall.get', owner_id=237897731, offset=0, count=10) is Vk.com API call:
import vkontakte
vk = vkontakte.API(token=access_token)
class VkWallPostListView(ListView):
model = VkWallPost
context_object_name = "vk_list"
def get_template_names(self):
return ["blog/vk_list.html"]
def get_queryset(self):
wallposts = VkWallPost.objects
if 'all_posts' not in self.request.GET:
wallposts = vk.get('wall.get', owner_id=237897731, offset=0, count=10)
for wallpost in wallposts:
wallpost.save()
#wallposts = wallposts.filter(text__startswith='RT')
tag = self.request.GET.get('tag', None)
if tag:
wallposts = wallposts.filter(tags=tag)
return wallposts
Also in this view i am trying to save results of API call to MongoDB right after the actual call:
for wallpost in wallposts:
wallpost.save()
But in browser i see an error:
Exception Value:
'int' object has no attribute 'save'
Exception Location: c:\Users\JOOMLER\BitNami_DjangoStack\django_mongo_test\blog\views.py in get_queryset, line 109
If i remove this two strings for cycle all works fine and shows on the fly data from Vk.com in browser. But i want to save it for later use. So, i assume the problem is how to save JSON response to MongoDB ?
That was simple and i am surprised that no answers:
i need to use raw Pymongo:
wallpost.save()
is not correct, because save django model with predefined fields
VkWallPost._get_collection().insert(vk_post)
this is correct - we use raw pymongo insert
Well, did you see what do you have in wallposts variable?
Cause, I think, error message is pretty clear: in cycle variable wallpost you have int value. And, of course, trying to call save() will throw exception. May be, objects in wallposts have integer indices, do you think?
Try to print what you have in wallposts.
I have code that looks like this:
def client = new groovyx.net.http.RESTClient('myRestFulURL')
def json = client.get(contentType: JSON)
net.sf.json.JSON jsonData = json.data as net.sf.json.JSON
def slurper = new JsonSlurper().parseText(jsonData)
However, it doesn't work! :( The code above gives an error in parseText because the json elements are not quoted. The overriding issue is that the "data" is coming back as a Map, not as real Json. Not shown, but my first attempt, I just passed the parseText(json.data) which gives an error about not being able to parse a HashMap.
So my question is: how do I get JSON returned from the RESTClient to be parsed by JsonSlurper?
The RESTClient class automatically parses the content and it doesn't seem possible to keep it from doing so.
However, if you use HTTPBuilder you can overload the behavior. You want to get the information back as text, but if you only set the contentType as TEXT, it won't work, since the HTTPBuilder uses the contentType parameter of the HTTPBuilder.get() method to determine both the Accept HTTP Header to send, as well was the parsing to do on the object which is returned. In this case, you need application/json in the Accept header, but you want the parsing for TEXT (that is, no parsing).
The way you get around that is to set the Accept header on the HTTPBuilder object before calling get() on it. That overrides the header that would otherwise be set on it. The below code runs for me.
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.6')
import static groovyx.net.http.ContentType.TEXT
def client = new groovyx.net.http.HTTPBuilder('myRestFulURL')
client.setHeaders(Accept: 'application/json')
def json = client.get(contentType: TEXT)
def slurper = new groovy.json.JsonSlurper().parse(json)
The type of response from RESTClient will depend on the version of :
org.codehaus.groovy.modules.http-builder:http-builder
For example, with version 0.5.2, i was getting a net.sf.json.JSONObject back.
In version 0.7.1, it now returns a HashMap as per the question's observations.
When it's a map, you can simply access the JSON data using the normal map operations :
def jsonMap = restClientResponse.getData()
def user = jsonMap.get("user")
....
Solution posted by jesseplymale workes for me, too.
HttpBuilder has dependencies to some appache libs,
so to avoid to add this dependencies to your project,
you can take this solution without making use of HttpBuilder:
def jsonSlurperRequest(urlString) {
def url = new URL(urlString)
def connection = (HttpURLConnection)url.openConnection()
connection.setRequestMethod("GET")
connection.setRequestProperty("Accept", "application/json")
connection.setRequestProperty("User-Agent", "Mozilla/5.0")
new JsonSlurper().parse(connection.getInputStream())
}
recently i`ve faced a problem parsing JSON responses, that contains html injections.
[{"Date":"\/Date(1316445326553+0400)\/",
"Dishes":null,"Id":103,"Name":"Menutka уже с Вами!",
"PictureId":130144,
"TextHtml":"<!DOCTYPE html PUBLIC '-\/\/W3C\/\/DTD XHTML 1.0 Transitional\/\/EN' 'http:\/\/www.w3.org\/TR\/xhtml1\/DTD\/xhtml1-transitional.dtd'>\u000a<html xmlns='http:\/\/www.w3.org\/1999\/xhtml'>\u000a<head>\u000a... etc",
"Type":1,"UserId":1,"UserName":"Администратор"}]
and tried to do JSON.parse response.body where response body is my JSON. It silenly obeys, but returns empty collection. I tried to validate this json on this site and it says "It s valid"
So i`m a bit confused about whats gone wrong.
PS this is my parse method:
def self.get(uri)
raw_url = BASE_URL+uri
url = "#{BASE_URL}"+CGI::escape(uri)
f = File.open('response.log', 'a')
start = Time.new
f.print "#{start.to_s}\t#{uri}"
resp = Net::HTTP.get_response(URI.parse(url))
stop = Time.new
f.puts "\t\t#{stop-start} seconds"
f.close
data = resp.body
begin
if data.blank? or data.include?('<html')
return {}
end
object = JSON.parse(data)
rescue JSON::ParserError
raise Exceptions::NothingReturned, "GET Error on #{raw_url}"
end
end
i'm not quite sure if it's that simple, but you're deliberately returning {} if your JSON contains a <html tag? what behavior do you want?
if you want to distinguish between html and json responses, just use the Content-Type response header