how to save the http.request curl in rails? - ruby-on-rails

I already managed to make a post request of curl in rails
I print on the console the response.body
{"access_token":"XXXXXXX","public_key":"XXXXXX","refresh_token":"XXXXXX","live_mode":false,"user_id":XXXX,"token_type":"bearer","expires_in":15552000,"scope":"offline_access read write"}
now I want to gurantee that data in a table in rails
How can you do that?
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end

If I understood correctly what you want is to make a HTTP request then parse the response and store it into a table (model) in your database. Well if that is the case:
require 'net/https'
uri = URI.parse("http://example.com/path")
// You can change the request method to whatever method you want
request = Net::HTTP::Post.new(uri.request_uri)
request.body = { //json hear in case you need it }
request.add_field 'token', 'XXXXX'
response = http.request(request).body
json_response = JSON.parse(response, symbolize_names: true)
You will have the response in json_response, then you only will have to store that information in the model you want:
Model.create(attribute_1: json_response[:parameter_1], attribute_2: json_response[:parameter_2]...)

Related

Rails Net::HTTP form data with custom headers

I am trying to send a file through form_data and set the Content-Type header as the content type of the file (image/png, image/jpeg, etc.) instead of multipart/form-data.
I have tried multiple ways, but here is my method:
def fetch(url, body, headers, limit, use_ssl, use_file_content_type)
raise HTTPRedirectLevelTooDeep, 'HTTP redirect too deep' if limit.zero?
headers[:'Content-Type'] = body['file'].content_type if use_file_content_type
uri = URI(url)
request = Net::HTTP::Post.new(url)
headers.each { |key, value| request[key.to_s] = value }
form_data = body.to_a
request.set_form form_data, 'multipart/form-data'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: use_ssl) do |http|
http.request(request)
end
case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then fetch(response['location'], body, headers, limit - 1)
else
response.error!
end
end
This sends the body just as I want it, but does not set the Content Type header correctly (it uses multipart/form-data). I also tried setting the header after setting the form data:
request['Content-Type'] = body['file'].content_type right before http.request(request) but it sends Content-Type: application/x-www-form-urlencoded.
I also tried setting the header in the Net::HTTP::Post.new method, or moving everything after request = inside the Net::HTTP.start method, but it still does not work for me. I also tried using request.set_form form_data, body['file'].content_type, but that just says invalid enctype: image/jpeg
One thing that sent the headers correctly was replacing this:
form_data = body.to_a
request.set_form form_data, 'multipart/form-data'
with
request.body = body.to_json
But this does not send the file as the external API I'm using expects it.
Do you have any suggestions of how I could tackle this? Thanks!

Make http POST request that return xml response and parsing XML fields

I want to make a http POST request that parse XML response and return the value of SessionId field that is inside XML. This is what I tried so far.
Ps: is there a way I can run this class from the console, in the way that I can see the response?
class Documents::CreateSession
def initialize()
#username = Rails.secrets.legal_doc.username
#password= Rails.secrets.legal_doc.password
end
def start
require "net/http"
require "uri"
uri = URI.parse("http://example.com/search")
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"userid" => #username, "password" => #password})
response = http.request(request)
end
end
I think that you can run your code the way that you have it now. Start a console and do the following:
obj = Documents::CreateSession.new
obj.start
For debugging purposes, you could put a binding.pry in the start method before you make your request.

Running a HTTP request with rails

It has been a while since I have used Rails. I currently have a curl request as follows
curl -X GET -H 'Authorization: Element TOKEN, User TOKEN' 'https://api.cloud-elements.com/elements/api-v2/hubs/marketing/ping'
All I am looking to do is to be able to run this request from inside of a rails controller, but my lack of understanding when it comes to HTTP requests is preventing me from figuring it out to how best handle this. Thanks in advance.
Use this method for HTTP requests:
def api_request(type , url, body=nil, header =nil )
require "net/http"
uri = URI.parse(url)
case type
when :post
request = Net::HTTP::Post.new(uri)
request.body = body
when :get
request = Net::HTTP::Get.new(uri)
when :put
request = Net::HTTP::Put.new(uri)
request.body = body
when :delete
request = Net::HTTP::Delete.new(uri)
end
request.initialize_http_header(header)
#request.content_type = 'application/json'
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') {|http| http.request request}
end
Your example will be:
api_request(:get, "https://api.cloud-elements.com/elements/api-v2/hubs/marketing/ping",nil, {"Authorization" => "Element TOKEN, User TOKEN" })
It would be something like the following. Note that the connection will be blocking, so it can tie up your server depending on how quickly the remote host returns the HTTP response and how many of these requests you are making.
require 'net/http'
# Let Ruby form a canonical URI from our URL
ping_uri = URI('https://api.cloud-elements.com/elements/api-v2/hubs/marketing/ping')
# Pass the basic configuration to Net::HTTP
# Note, this is not asynchronous. Ruby will wait until the HTTP connection
# has closed before moving forward
Net::HTTP.start(ping_uri.host, ping_uri.port, :use_ssl => true) do |http|
# Build the request using the URI as a Net::HTTP::Get object
request = Net::HTTP::Get.new(ping_uri)
# Add the Authorization header
request['Authorization'] = "Element #{ELEMENT_TOKEN}, User #{user.token}"
# Actually send the request
response = http.request(request)
# Ruby will automatically close the connection once we exit the block
end
Once the block exits, you can use the response object as necessary. The response object is always a subclass (or subclass of a subclass) of Net::HTTPResponse and you can use response.is_a? Net::HTTPSuccess to check for a 2xx response. The actual body of the response will be in response.body as a String.

Why Rails (current 4.0) fails to interpret nested JSON (from a HTTP POST)?

I am writing a simple client server application (using only JSON API) with Ruby (client) and Rails (server).
When trying to create a game from client, I am using:
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"tttgame" => {"name" => "Marius"}})
resp = http.request(request)
On server side (tttgames_controller.rb) I have:
# POST /tttgames
# POST /tttgames.json
def create
#tttgame = Tttgame.new(tttgame_params)
...
end
...
def tttgame_params
params.require(:tttgame).permit(:name)
end
Logs on server are:
Started POST "/tttgames.json" for 127.0.0.1 at 2013-10-05 12:58:44 +0300
Processing by TttgamesController#create as JSON
Parameters: {"tttgame"=>"{\"name\"=>\"Marius\"}"}
Completed 500 Internal Server Error in 0ms
NoMethodError (undefined method `stringify_keys' for "{\"name\"=>\"Marius\"}":String):
app/controllers/tttgames_controller.rb:33:in `create'
How can I fix this? All examples from the Internet are looking the same. Thanks!
Both methods set_form_data and post_form are encoding data using format x-www-form-urlencoded. Check here.
Examples that are provided do not contain nested hashes.
I have found here an example, under the REST methods section, which works very well.
Thus, in order to get on server a valid structure with nested hashes, the client should use square brackets:
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"tttgame[name]" => “Marius”)
resp = http.request(request)
or much simpler:
uri = URI.parse(url)
resp = Net::HTTP.post_form(uri, {"tttgame[name]" => “Marius”})
This will generate on server
Parameters: {"tttgame"=>{"name"=>"Marius"}}
You might want to do this instead. It's even more compact.
uri = URI.parse(url)
resp = Net::HTTP.post_form(uri, "tttgame" => {"name" => "Marius"})
From http://ruby-doc.org/stdlib-2.0.0/libdoc/net/http/rdoc/Net/HTTP.html#label-POST+with+Multiple+Values
UPDATE: In addition, your String is not a valid JSON. It needs to be "{\"name\":\"Marius\"}" instead.
You need to parse that response, because right now it is a String ("{\"name\"=>\"Marius\"}") but you actually need a Hash ({"name" => "Marius"}).
Therefore #stringify_keys fails because it is a method that operates on a Hash.
So do a:
#tttgame = Tttgame.new(JSON.parse(tttgame_params))
instead. This will turn your serialized JSON response into a Hash from a String.

Rails 3 Post to external web service

Lets say I have a blog post that a user is creating and I want to send all of the data to an external web service as XML with a specific schema so it can be ingested into that web service.
I have been looking into the ActionDispatch::Request
And I read this Using Ruby on Rails to POST JSON/XML data to a web service post and answer
However I got an error saying content_type was not a valid method for request. So I changed that line to call the header method and create a header for content-type with the appropriate information
Ok... so now where to go?
This is my code so far:
url= URI.parse('http://10.29.3.47:8080/ingest')
response = Net::HTTP::Post.new(url.path)
request.headers["Content-Type"] = 'application/json'
request.body = 'all of my xml data and schema which is far too long to type here'
response = Net::HTTP.start(url.host, url.port) {|http| http.request(request)}
assert_equal '201 Created', response.get_fields('Status')
I get an error saying that request.body is also not a valid method call, but when I look at the API the only thing matching body is "body()" which does not take arguments. So how do I pass the content of my post to the web service?
Thank you for the help!
You had response = Net::HTTP::Post.new(url.path) instead of request = Net::HTTP::Post.new(url.path) and you add headers with add_field.
require 'net/http'
require 'uri'
url= URI.parse('http://10.29.3.47:8080/ingest')
request = Net::HTTP::Post.new(url.path)
request.add_field 'Content-Type', 'application/json'
request.body = 'all of my xml data and schema which is far too long to type here'
response = Net::HTTP.start(url.host, url.port) {|http| http.request(request)}

Resources