Adding content-length to an API post request using Rails - ruby-on-rails

I'm trying to post some data to the Google Places api. However when I run the code (below) I receive a 411 Length Required error. Does anyone know how to resolve this using the code below. Thanks
require 'rubygems'
require 'httparty'
class Partay
include HTTParty
base_uri 'https://maps.googleapis.com/maps/api/place/add/json?sensor=false&key=API_Key'
end
#add to google API
options = {
:location => {
:lat => '33.71064',
:lng => '-84.479605'
}
}
{
:accuracy => '50',
:name=>"Rays NewShoeTree",
:types=> "shoe_store",
:language=> "en-AU"
}
puts Partay.post('/maps/api/place/add/json?sensor=false&key=API_Key', options)

You need to specify a body in the post. Even just nil or an empty hash, then HTTParty will include the Content-Length header.

Related

How to format HTTParty POST request?

I've been playing around with API calls for a project I'm working on and I'm getting a problem when I try to pass some JSON to a POST request. The call works in Postman, but I just can't figure out how to format it in Ruby. Here's my code:
require 'httparty'
require 'json'
require 'pp'
#use the HTTParty gem
include HTTParty
#base_uri 'https://app.api.com'
#set some basic things to make the call,
#apiUrl = "https://app.api.com/"
#apiUrlEnd = 'apikey=dontStealMePls'
#apiAll = "#{#apiUrl}#{#apiUrlEnd}"
#apiTest = "https://example.com"
def cc_query
HTTParty.post(#apiAll.to_s, :body => {
"header": {"ver": 1,"src_sys_type": 2,"src_sys_name": "Test","api_version": "V999"},
"command1": {"cmd": "cc_query","ref": "test123","uid": "abc01", "dsn": "abcdb612","acct_id": 7777}
})
end
def api_test
HTTParty.post(#apiTest.to_s)
end
#pp api_test()
pp cc_query()
This code gives me this error:
{"fault"=>
{"faultstring"=>"Failed to execute the ExtractVariables: Extract-Variables",
"detail"=>{"errorcode"=>"steps.extractvariables.ExecutionFailed"}}}
I know that error because I would get it if I tried to make a call without any JSON in the body of the call (through Postman). So from that I assume that my code above is not passing any JSON when making an API call. Am I formatting my JSON incorrectly? Am I even formatting the .post call correctly? Any help is appreciated! :)
the api_test() method just makes a POSt call to example.com and it works (saving my sanity).
Just use HTTParty as a mixin instead in a class instead:
require 'httparty'
class MyApiClient
include HTTParty
base_uri 'https://app.api.com'
format :json
attr_accessor :api_key
def initalize(api_key:, **options)
#api_key = api_key
#options = options
end
def cc_query
self.class.post('/',
body: {
header: {
ver: 1,
src_sys_type: 2,
src_sys_name: 'Test',
api_version: 'V999'
},
command1: {
cmd: 'cc_query',
ref: 'test123',
uid: 'abc01',
dsn: 'abcdb612',
acct_id: 7777
}
},
query: {
api_key: api_key
}
)
end
end
Example usage:
MyApiClient.new(api_key: 'xxxxxxxx').cc_query
When you use format :json HTTParty will automatically set the content type and handle JSON encoding and decoding. I'm guessing thats where you failed.

http Post request And declaration of authorization header in rails

I am trying to perform an HTTP authorization using Ruby on Rails. Here is what I'm trying:
res = http.post(uri.request_uri,
:Authorization => cobSessionToken,
"coBrandSessionCredential=loginToken=#{cobSessionToken}&userLogin=#{login}&userPassword=#{password}")
render :json => {"isValid" => true, "Body" => JSON.parse(res.body)}
This doesn't seem to work. How can I perform an authorization?
how about something like this?
url = URI.parse('https://my.url.com/path')
req = Net::HTTP::Post.new(url.path)
req.basic_auth 'user', 'pass'
req.use_ssl = true
req.form_data({'key1' => 'val1', 'key2' => 'val2'})
resp = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
puts resp
I would recommend using something like postman (its a free google program you can get at the google store) to make sure the error is not on the server side. Use Net:http it comes with ruby so you do not need to install it but you have to require it.
Require it by:
require "net/http"
require "uri"
Use this cheatsheet I think you need basic_auth.rb You will see how to form the request.

How do I use GET and POST on Github using access tokens?

I am using OmniAuth to authenticate a user via Github. OmniAuth provides access tokens. Now I want to send the GET or POST request to Github. I don't want to use any gems, I want to do with Net::HTTP. I did it like this:
<%consumer = OAuth::Consumer.new("mshsD0jpgcYwwOEcTW5ZTA", "V6KTqllY5jS392pj4FNFCb5EiOM8DaFzVwr9cS54XQ", { :site => "https://api.github.com", :request_token_path => '/oauth/request_token', :access_token_path => '/oauth/access_token', :authorize_path => '/oauth/authorize', :scheme => :header })%>
<%access_token = OAuth::AccessToken.new(consumer,auth.token,auth.secret)%>
The same I previously did for Twitter worked fine but now I am getting the following error:
uninitialized constant ActionView::CompiledTemplates::OAuth
Even in the same application the same thing is working for Twitter but not for Github.
I searched through Google but found nothing that helped.
You should be using OAuth2 instead of OAuth. I'd actually recommend using Octokit, it's easy to use and Wynn works for GitHub now so part of his job is keeping it up to date. :)
If you want to use Net::HTTP (although I can't imagine why), you can actually do that without any gems. Just put the token you got from OmniAuth in the request's "Authentication" header.
require 'net/https'
require 'uri'
uri = uri = URI.parse("https://api.github.com/users/username")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
headers = { "Authentication" => "token" }
request = Net::HTTP::Get.new(uri.request_uri, headers)
response = http.request(request)
response.body # => A string containing the JSON response
Seeing as you're already using Omniauth and are familiar with it, I'd recommend using the omniauth-github strategy: https://github.com/intridea/omniauth-github

Ruby: HTTParty: can't format XML POST data correctly?

NOTE: "object" is a placeholder work, as I don't think I should be saying what the controller does specifically.
so, I have multiple ways of calling my apps API, the following works in the command line:
curl -H 'Content-Type: application/xml' -d '<object><name>Test API object</name><password>password</password><description>This is a test object</description></object>' "http://acme.example.dev/objects.xml?api_key=1234"
the above command generates the following request in the devlog:
Processing ObjectsController#create to xml (for 127.0.0.1 at 2011-07-07 09:17:51) [POST]
Parameters: {"format"=>"xml", "action"=>"create", "api_key"=>"1234", "controller"=>"objects",
"object"=>{"name"=>"Test API object", "description"=>"This is a test object", "password"=>"[FILTERED]"}}
Now, I'm trying to write tests for the actions using the API, to make sure the API works, as well as the controllers.
Here is my current (broken) httparty command:
response = post("create", :api_key => SharedTest.user_api_key, :xml => data, :format => "xml")
this command generates the following request in the testlog:
Processing ObjectsController#create to xml (for 0.0.0.0 at 2011-07-07 09:37:35) [POST]
Parameters: {
"xml"=>"<object><name><![CDATA[first post]]></name>
<description><![CDATA[Things are not as they used to be]]></description>
<password><![CDATA[WHEE]]></password>
</object>",
"format"=>"xml",
"api_key"=>"the_hatter_wants_to_have_tea1",
"action"=>"create",
"controller"=>"objects
So, as you can see, the command line command actually generates the object hash from the xml, whereas the httparty command ends up staying in xml, which causes problems for the create method, as it needs a hash.
Any ideas / proper documentation?
Current documentation says that post takes an url, and "options" and then never says what options are available
**EDIT:
as per #Casper's suggestion, my method now looks like this:
def post_through_api_to_url(url, data, api_key = SharedTest.user_api_key)
response = post("create", {
:query => {
:api_key => api_key
},
:headers => {
"Content-Type" => "application/xml"
},
:body => data
})
ap #request.env["REQUEST_URI"]
assert_response :success
return response
end
unfortunately, the assert_response fails, because the authentication via the api key fails.
looking at the very of of the request_uri, the api_key isn't being set properly... it shows:
api_key%5D=the_hatter_wants_to_have_tea1"
but it should just be equals, without the %5D (right square bracket)
I think this is how you're supposed to use it:
options = {
:query => {
:api_key => 1234
},
:headers => {
"Content-Type" => "application/xml"
},
:body => "<xmlcode>goes here</xmlcode>"
}
post("/create", options)
Forgive me for being basic about it but if you only want to send one variable as a parameter, why don't you do as Casper suggests, but just do:
post("/create?api_key=1234", options)
Or rather than testing HTTParty's peculiarities in accessing your API, perhaps write your tests using Rack::Test? Very rough example...
require "rack/test"
require "nokogiri"
class ObjectsTest < Test::Unit::TestCase
include Rack::Test::Methods
def app
MyApp.new
end
def create_an_object(o)
authorize "x", "1234" # or however you want to authenticate using query params
header 'Accept', 'text/xml'
header 'Content-Type', 'text/xml'
body o.to_xml
post "/create"
xml = Nokogiri::XML(last_response.body)
assert something_logic_about(xml)
end
end

Changing Content-Type to JSON using HTTParty

I am trying to use Ruby on Rails to communicate with the Salesforce API. I can fetch data easily enough but I am having problems posting data to the server. I am using HTTParty as per Quinton Wall's post here:
https://github.com/quintonwall/omniauth-rails3-forcedotcom/wiki/Build-Mobile-Apps-in-the-Cloud-with-Omniauth,-Httparty-and-Force.com
but all I seem to be able to get from the salesforce server is the error that I am submitting the body as html
{"message"=>"MediaType of 'application/x-www-form-urlencoded' is not supported by this resource", "errorCode"=>"UNSUPPORTED_MEDIA_TYPE"}
the responsible code looks like:
require 'rubygems'
require 'httparty'
class Accounts
include HTTParty
format :json
...[set headers and root_url etc]
def self.save
Accounts.set_headers
response = (post(Accounts.root_url+"/sobjects/Account/", :body => {:name => "graham"}.to_json))
end
end
anyone have an idea why the body should be being posted as html and how to change this so that it definitely goes as json so that salesforce doesn't reject it?
Any help would be appreciated. cheers
The Content-Type header needs to be set to "application/json". This can be done by inserting :headers => {'Content-Type' => 'application/json'} as a parameter to post, ie:
response = post(Accounts.root_url+"/sobjects/Account/",
:body => {:name => "graham"}.to_json,
:headers => {'Content-Type' => 'application/json'} )
You have to set the Content-Type header to application/json. I haven't used HTTParty, but it looks like you have to do something like
response = (post(Accounts.root_url+"/sobjects/Account/", :body => {:name => "graham"}.to_json) , :options => { :headers => { 'Content-Type' => 'application/json' } } )
I'm somewhat surpised that the format option doesn't do this automatically.

Resources