I am writing a code that send http post request. Now I write xml body in my code, and its working correctly.
But if I want to send request using xml file I get
undefined method `bytesize' for #
Did you mean? bytes
My code below
require 'net/http'
request_body = <<EOF
<xml_expamle>
EOF
uri = URI.parse('http://example')
post = Net::HTTP::Post.new(uri.path, 'content-type' => 'text/xml; charset=UTF-8')
post.basic_auth 'user','passcode'
Net::HTTP.new(uri.host, uri.port).start {|http|
http.request(post, request_body) {|response|
puts response.body
}
}
**But if I want to make send file**
require 'net/http'
request_body = File.open('example/file.xml')
uri = URI.parse('http://example')
post = Net::HTTP::Post.new(uri.path, 'content-type' => 'application/xml; charset=UTF-8')
post.basic_auth 'user','passcode'
Net::HTTP.new(uri.host, uri.port).start {|http|
http.request(post, request_body) {|response|
puts response.body
}
}
I get
undefined method `bytesize' for #
Did you mean? bytes
You need to load the file content to memory if you want to use it as a request body, use #read method:
request_body = File.open('example/file.xml').read
and it'll work.
I keep getting a
400 "Bad Request" (Net::HTTPServerException)
error whenever I try to add a content-type header from various methods.
I've seen several different examples and I can't get any to work. My goal is to add a content type of JSON to my request. Without the header, my request doesn't error:
def post_data(notice)
uri = URI('my uri is here')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new("#{uri.path}?#{uri.query}")
text = notice
req.add_field('Content-Type', 'application/json')
req.body = "{\"sensu_payload\" = #{payload(text).to_json}}"
response = http.request(req)
verify_response(response)
end
I've also tried this method of adding a header:
request = Net::HTTP::Post.new(#path, initheader = {'Content-Type' =>'application/json'})
Use uri.path instead of #path:
request = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
Instead of add_field, I think you should use the hash [] form:
req['Content-Type'] = 'application/json'
See the "Setting Headers" example in the documentation and []=.
Also, using:
"#{uri.path}?#{uri.query}"
is never a good idea. String concatenation can't manage the complexities of correctly encoding illegal values in a query, which can break a request. Consider doing something like this instead:
require 'uri'
require 'uri'
foo = URI('http://www.example.com') # => #<URI::HTTP http://www.example.com>
foo.query = URI::encode_www_form({'bar' => 'path/to/file', 'baz' => 'this & that'})
foo.to_s # => "http://www.example.com?bar=path%2Fto%2Ffile&baz=this+%26+that"
Beyond that, I'd recommend using any of the other HTTP-client gems available. They make it much easier to deal with unexpected situations, like redirects and retries than Net::HTTP. It's more like the building block for features that aren't available other ways.
I'm trying to send get request with:
require "net/https"
require "uri"
...
uri = "https://graph.facebook.com/v2.2/#{event_id}?access_token=#{access_token}"
uri = URI.parse(uri)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
response.body
Facebook sent me an acces_token with | char, and because of it uri = URI.parse(uri) throws an error: URI::InvalidURIError: bad URI(is not URI?) https:/ ....
Is there any other parser, or should I manually extract these host, port, request_uri values? What's the best way of fixing it?
access_token looks like 141112112181111|9Alz3xW7P0CQ_DRomJN2oMeiwXs
event_id is for example 385101904985590
edit: just realized that it's structure is APP_ID|some_token
Have you tried encoding the URI with URI#encode?
uri = 'http://foobar.com?foo=something|weird'
uri = URI.encode(uri)
uri = URI.parse(uri) => #<URI::HTTP:0x007fe2f48775b0 URL:http://foobar.com?foo=something%7Cweird>
Don't try to inject variables into URI query parameters, especially tokens and keys and such as that's a good route to creating an invalid one. Instead, rely on the URI class and let it handle as much as possible.
require 'uri'
event_id = 1
access_token = 'foo|bar'
uri = URI.parse("https://graph.facebook.com/v2.2/#{event_id}")
uri.query = URI.encode_www_form(['access_token', access_token])
uri.to_s # => "https://graph.facebook.com/v2.2/1?access_token&foo%7Cbar"
If you want something more full-featured, Addressable::URI is very nice.
See "Parsing string to add to URL-encoded URL" for more information.
I am not able to get the xml response after triggering 'GET' request using Ruby language.My Current Code is as follows:
require 'net/https'
require 'uri'
require 'base64'
base_url = '<URL>'
app_guid = '<App GUID Value>'
format = "xml"
# Example using bug.fetch
params = {
"appGUID" => app_guid,
"format" => format,
"method" => "bug.fetch",
"bugId" => "1234567"
}
puts "XML Response"
res = Net::HTTP.post_form(URI.parse(base_url), params)
puts res.body
As Frederick notes, your code is making a POST request. If you want to use GET do:
uri = URI.parse(base_url)
uri.query = URI.encode_www_form(params)
res = Net::HTTP.get_response(uri)
If you still encounter errors, you may wish to use this alternative syntax:
uri = URI.parse(base_url)
uri.query = URI.encode_www_form(params)
conn = Net::HTTP.new(uri.host, uri.port)
conn.use_ssl = true
res = conn.get uri.request_uri
How do I send a JSON request in ruby? I have a JSON object but I dont think I can just do .send. Do I have to have javascript send the form?
Or can I use the net/http class in ruby?
With header - content type = json and body the json object?
uri = URI('https://myapp.com/api/v1/resource')
body = { param1: 'some value', param2: 'some other value' }
headers = { 'Content-Type': 'application/json' }
response = Net::HTTP.post(uri, body.to_json, headers)
require 'net/http'
require 'json'
def create_agent
uri = URI('http://api.nsa.gov:1337/agent')
http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
req.body = {name: 'John Doe', role: 'agent'}.to_json
res = http.request(req)
puts "response #{res.body}"
rescue => e
puts "failed #{e}"
end
HTTParty makes this a bit easier I think (and works with nested json etc, which didn't seem to work in other examples I've seen.
require 'httparty'
HTTParty.post("http://localhost:3000/api/v1/users", body: {user: {email: 'user1#example.com', password: 'secret'}}).body
This works on ruby 2.4 HTTPS Post with JSON object and the response body written out.
require 'net/http' #net/https does not have to be required anymore
require 'json'
require 'uri'
uri = URI('https://your.secure-url.com')
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
request.body = {parameter: 'value'}.to_json
response = http.request request # Net::HTTPResponse object
puts "response #{response.body}"
end
real life example, notify Airbrake API about new deployment via NetHttps
require 'uri'
require 'net/https'
require 'json'
class MakeHttpsRequest
def call(url, hash_json)
uri = URI.parse(url)
req = Net::HTTP::Post.new(uri.to_s)
req.body = hash_json.to_json
req['Content-Type'] = 'application/json'
# ... set more request headers
response = https(uri).request(req)
response.body
end
private
def https(uri)
Net::HTTP.new(uri.host, uri.port).tap do |http|
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
end
end
project_id = 'yyyyyy'
project_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
url = "https://airbrake.io/api/v4/projects/#{project_id}/deploys?key=#{project_key}"
body_hash = {
"environment":"production",
"username":"tomas",
"repository":"https://github.com/equivalent/scrapbook2",
"revision":"live-20160905_0001",
"version":"v2.0"
}
puts MakeHttpsRequest.new.call(url, body_hash)
Notes:
in case you doing authentication via Authorisation header set header req['Authorization'] = "Token xxxxxxxxxxxx" or http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html
A simple json POST request example for those that need it even simpler than what Tom is linking to:
require 'net/http'
uri = URI.parse("http://www.example.com/search.json")
response = Net::HTTP.post_form(uri, {"search" => "Berlin"})
I like this light weight http request client called `unirest'
gem install unirest
usage:
response = Unirest.post "http://httpbin.org/post",
headers:{ "Accept" => "application/json" },
parameters:{ :age => 23, :foo => "bar" }
response.code # Status code
response.headers # Response headers
response.body # Parsed body
response.raw_body # Unparsed body
It's 2020 - nobody should be using Net::HTTP any more and all answers seem to be saying so, use a more high level gem such as Faraday - Github
That said, what I like to do is a wrapper around the HTTP api call,something that's called like
rv = Transporter::FaradayHttp[url, options]
because this allows me to fake HTTP calls without additional dependencies, ie:
if InfoSig.env?(:test) && !(url.to_s =~ /localhost/)
response_body = FakerForTests[url: url, options: options]
else
conn = Faraday::Connection.new url, connection_options
Where the faker looks something like this
I know there are HTTP mocking/stubbing frameworks, but at least when I researched last time they didn't allow me to validate requests efficiently and they were just for HTTP, not for example for raw TCP exchanges, this system allows me to have a unified framework for all API communication.
Assuming you just want to quick&dirty convert a hash to json, send the json to a remote host to test an API and parse response to ruby this is probably fastest way without involving additional gems:
JSON.load `curl -H 'Content-Type:application/json' -H 'Accept:application/json' -X POST localhost:3000/simple_api -d '#{message.to_json}'`
Hopefully this goes without saying, but don't use this in production.
The net/http api can be tough to use.
require "net/http"
uri = URI.parse(uri)
Net::HTTP.new(uri.host, uri.port).start do |client|
request = Net::HTTP::Post.new(uri.path)
request.body = "{}"
request["Content-Type"] = "application/json"
client.request(request)
end
data = {a: {b: [1, 2]}}.to_json
uri = URI 'https://myapp.com/api/v1/resource'
https = Net::HTTP.new uri.host, uri.port
https.use_ssl = true
https.post2 uri.path, data, 'Content-Type' => 'application/json'
Using my favourite http request library in ruby:
resp = HTTP.timeout(connect: 15, read: 30).accept(:json).get('https://units.d8u.us/money/1/USD/GBP/', json: {iAmOne: 'Hash'}).parse
resp.class
=> Hash