I have a few models in Ruby that I need to send to a Java/RestEasy server via HTTParty/Put.
configuration_mapping.rb:
def as_json(options = {})
{:configGroup => #group, :coordinates => {#key => #value}}
end
def self.put(endpoint, content, tier = 'nursery')
response = HTTParty.put(base_uri + endpoint, json_payload(content))
end
def self.json_payload(content)
{
:body => content.to_json,
:format => :json,
:headers => {"Content-Type" => "application/json", "content-type" => "application/json", "Accept" => "application/json"}
}
end
The JSON gets double escaped:
{ :body=>" {
\"configGroup\":\"test\",
\"coordinates\":{
\"Integration Test Key\":\"moo\"
} } ", :format=>:json, :headers=>{" Content-Type"=>"application/json", "content-type"
=>"application/json", "Accept" =>"application/json" } }
And Jackson JSON parser borks:
2011-11-27 15:34:11,179 ERROR [tp-1442358158-0] [REPORT] []
[asy.core.SynchronousDispatcher] Failed executing PUT
/v1/groups/test/mappings;tester=Integration
Test;tier=qa;timeStamp=-4712-01-01
org.jboss.resteasy.spi.ReaderException:
org.codehaus.jackson.map.JsonMappingException: Can not deserialize
instance of java.lang.String out of START_OBJECT token at [Source:
org.mortbay.jetty.HttpParser$Input#4092fef5; line: 1, column: 22] at
I tried letting httparty convert to json for me, thinking httparty escaped the characters, writing my own as_json method, but this is the output which is not the json I wanted, the wrong fields are in here and my as_json method is not called:
{:body=>Config::Client::ConfigurationMapping:0x00000100c78930
#dimensions={"tester"=>"Integration Test", "tier"=>"qa",
"timeStamp"=>"-4712-01-01"}, #key="Integration Test Key",
#group="test", #value="moo">, :format=>:json,
:headers=>{"Content-Type"=>"application/json",
"content-type"=>"application/json", "Accept"=>"application/json"}}
What is causing the string to become double escaped?
I figured out the problem, my json wasn't formatted correctly. I reformatted the packet and it worked.
Related
I have created REST Api in Ruby on Sinatra platform. I am testing the service with Postman and whatever JSON form I try to POST I keep getting an error 400 Invalid JSON SUCKER. The error is defined on the back end in case of invalid JSON form. Please take a look at the back end and tell me what am I doing wrong.
I have to mention that GET method works with Postman and cURL from the command line while POST works only if I use it with cURL but NOT in POSTMAN.
#server.rb
require 'sinatra'
require 'mongoid'
require 'sinatra/namespace'
require 'sinatra/base'
#require 'json'
before do
content_type :json
headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST', 'PATCH']
end
#load database config
Mongoid.load! "mongoid.config"
#Class Company
class Company
include Mongoid::Document
field :compid, type: String
field :name, type: String
field :address, type: String
field :city, type: String
# validates :compid, presence: true
# validates :name, presence: true
index({ compid:1 }, { unique: true, name: "compid_index" })
index({ name: 'text' })
scope :name, -> (name) { where(name: /^#{name}/) } # this could be changed to /^#{title}/i to make case insensitive searcg =end
scope :compid, -> (compid) { where(compid: compid) }
end
#Serializers
class Serializer
def initialize(company)
#company = company
end
def as_json(*)
data ={
id:#company.compid.to_s,
name:#company.name,
address:#company.address,
city:#company.city,
}
data[:errors] = #company.errors if#company.errors.any?
data
end
end
# Endpoints
get '/' do
'List of all Companies'
end
namespace '/api/v1' do
before do
content_type 'application/json'
end
helpers do
def base_url
#base_url ||= "#{request.env['rack.url_scheme']}://{request.env['HTTP_HOST']}"
end
def json_params
begin
JSON.parse(request.body.read)
rescue
halt 400, { message:'Invalid JSON' }.to_json
end
end
end
get '/companies' do
companies = Company.all
[ :name, :compid,].each do |filter|
companies = companies.send(filter, params[filter]) if params[filter]
end
#put it through the serializer not to get all te atributes
companies.map { |company| Serializer.new(company) }.to_json
end
get '/companies/:compid' do |compid| #get the details about the company by searching with compid
company = Company.where(compid: compid).first
halt(404, { message:'Company Not Found'}.to_json) unless company
Serializer.new(company).to_json
end
post '/companies' do
company = Company.new(json_params)
if company.save
response.headers['Location'] = "#{base_url}/api/v1/companies{company.copmid}" # "{company.id}"
status 201
else
status 422
body Serializer.new(company).to_json
end
end
The data that I GET with the Postman looks like this:
[{"id":"5a1271f7943e8a0f5fd76008","name":"The Power Of Habit","address":"Charles Duhigg Vej","city":"Viborg"}]
I have tried to POST data in various forms:
[{"id":"5a1271f79asdd76008","name":"The Power Of Habit","address":"Charles Duhigg Vej","city":"Viborg"}]
{"id":"5a1271f79asdd76008","name":"The Power Of Habit","address":"Charles Duhigg Vej","city":"Viborg"}
[{"compid":"5a1271f79asdd76008","name":"The Power Of Habit","address":"Charles Duhigg Vej","city":"Viborg"}]
{"compid":"5a1271f79asdd76008","name":"The Power Of Habit","address":"Charles Duhigg Vej","city":"Viborg"}
I am trying to send a patch request to edit a video using vimeo api using ruby. The request is successful but vimeo is not able to read my the payload(the title and description), that is, the the title and the description is not getting changed. I have used HTTParty, RestClient as well as Net::HTTP but none of it works. Below are my code that i have implemented to send a patch request,
RestClient
payload = {"description" => "Test Description", "name" => "Test Video"}
res = RestClient.patch(
vimeo_edit_url,
payload.to_s,
{ "Authorization" => auth })
NET::HTTP
options = {'description' => "Test Description", 'name' => "Test Video"}
edit_req = Net::HTTP::Patch.new(vimeo_edit_url, initheader = { "Authorization" => auth})
edit_req.data = options.to_s
edit_uri = URI(vimeo_edit_url)
edit_http = Net::HTTP.new(edit_uri.host, edit_uri.port)
edit_http.use_ssl = true
edit_http.verify_mode = OpenSSL::SSL::VERIFY_PEER
edit_response = edit_http.request(edit_req)
Usually the response will be a 200 OK with the updated video details but I get a 200 OK with video details(title and description not being changed). It is as if like vimeo is not able to read my payload.
You probably want to be passing payload, not payload.to_s.
That .to_s is turning your nicely arranged hash into a weird rubyified string, and all of the HTTP libraries you mentioned will accept a hash and handle the conversion for you.
Here's what some different representations look like in an irb session:
>> payload = {"description" => "Test Description", "name" => "Test Video"}
>> payload
=> {"description"=>"Test Description", "name"=>"Test Video"}
>> payload.to_s
=> "{"description"=>"Test Description", "name"=>"Test Video"}"
>> require 'json'
=> true
>> payload.to_json
=> "{"description":"Test Description","name":"Test Video"}"
I'm using Grape on Padrino to make a test API for my mobile app.
How can I specify the type of my JSON object?
Here is how i do it, but every returned value is a String:
module Acme
module Api
class Ping < Grape::API
format :json
get '/user/112132a08s245c/availability_list' do
{
"availability_list"=> [
{
:type=> "OOO",
:from_date=> "21-12-2004",
:to_date=> "21-23-2007",
:all_day=> "false"
},
{
:type=> "WFH",
:from_date=> "21-12-2004",
:to_date=> "21-23-2007",
:all_day=> "false"
}
]
}
end
get '/user/112132a08s245c/issues' do
{
"issues"=> [
{
:issure_id=> "1ab300co221",
:title=> "No water",
:description=> "No water in kitchen",
:severity=> "low",
"location" => {
:lat => "37.4224764",
:lng => "-122.0842499"
}
},
{
:issure_id=> "1ab300co222",
:title=> "No fire",
:description=> "No fire in kitchen",
:severity=> "low",
"location" => {
:lat => "37.4224764",
:lng => "-122.0842499"
}
}
]
}
end
end
end
Meditate on this:
require 'json'
foo = {'a' => 1}
foo.class # => Hash
str = JSON[foo] # => "{\"a\":1}"
str.class # => String
bar = JSON[str] # => {"a"=>1}
bar.class # => Hash
You need to read the JSON spec. JSON serializes data into a string because objects can't be transferred between disparate languages. When it sees an object the parser serializes it into a string. When the incoming string is received and passed on to the parser, it knows it has to convert the string back to an object.
I am trying to write a Jekyll extension that will embed comments from a Blogger blog.
I am able to fetch the comments feed as JSON, and process it enough to pull out the total number of comments. However, I have not figured out how to process each comment in the feed.
json_url = "http://www.blogger.com/feeds/8505008/593465383646513269/comments/default/?alt=json"
json_rep = Net::HTTP.get_response(json_url)
json_rep = JSON.parse(json_rep.body)
json_rep['feed']['openSearch$totalResults']['$t'] # => "4"
json_rep['feed']['entry'].class # => Array
json_rep['feed']['entry'].length
# => Liquid Exception: undefined method `length' for nil:NilClass in post
This is my first time writing any code in Ruby. What am I doing wrong?
Here are the relevant parts of the JSON I am trying to parse.
{
"feed": {
"openSearch$totalResults": {
"$t": "4"
},
"entry": [
{
"id": {
"$t": "tag:blogger.com,1999:blog-8505008.post-491866073982779922"
},
"published": {
"$t": "2013-01-08T15:23:47.322-04:00"
},
"content": {
"type": "html",
"$t": "Recently, my sister has updated it more than I have. \u00dcber-fail on my part. :p"
}
}
]
}
}
This is what you should look at doing:
require 'rubygems'
require 'json'
require 'net/http'
require 'net/https'
require 'uri'
url = "http://www.blogger.com/feeds/8505008/593465383646513269/comments/default/?alt=json"
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
json_rep = JSON.parse(response.body)
puts json_rep['feed']['openSearch$totalResults']['$t']
entries = json_rep['feed']['entry']
entries.each do |entry|
puts entry["id"]["$t"]
#add what ever code you like here
end
This outputs:
4
tag:blogger.com,1999:blog-8505008.post-491866073982779922
tag:blogger.com,1999:blog-8505008.post-4792479891671746788
tag:blogger.com,1999:blog-8505008.post-4766604955439002209
tag:blogger.com,1999:blog-8505008.post-5484003770204916000
This seems to work fine:
views/index.haml:
%form{:method => 'POST' :action => '/'}
%label{:for => 'name'} Name:
%input{:type => 'text, :value => #values[:name] || ""}
%input{:type => 'submit'}
app.rb:
post '/' do
#values = params
haml :review
end
views/review.rb
Hello #{params[:name]}!
However, when I try to send my post-data to the same view on a different URL I get an error, or in other words:
app.rb:
post '/' do
#values = params
redirect '/review'
end
get '/review' do
#values = params
haml :review
end
The data is not going through, but no error is raised.
How do I send the post-data across pages like this? Ideally, I do not want to create a database.
You can store the parameters in a session or specify the query string explicitly. Browser Redirect from Sinatra Documentation
As specified in the documentation, you may use sessions or convert the POST params to a query string and use it in the redirect method. A crude example would be:
Say the POST params hash inside the '/' block is:
{
:name => "Whatever",
:address => "Wherever"
}
This hash can be made into a string like so:
query = params.map{|key, value| "#{key}=#{value}"}.join("&")
# The "query" string now is: "name=Whatever&address=Wherever"
Now use this inside the post '/' do
redirect to("/review?#{query}")