How to get API and manipulate it - ruby

With Ruby, no Rails, how can I call an API such as http://api.anapi.com/, and later get a value and check if it is greater than 5?
If it contains an array called "anarray" which contains hashes, in one of those hashes I want to get to the value of the key "key".
Right now I use:
require "net/https"
require "uri"
uri = URI.parse("http://api.cryptocoincharts.info/tradingPair/eth_btc")
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
puts response.body
And I get: #<StringIO:0x2cadb90>
Figured it out:
# http://ruby-doc.org/stdlib-2.0.0/libdoc/open-uri/rdoc/OpenURI.html
require 'open-uri'
# https://github.com/flori/json
require 'json'
# http://stackoverflow.com/questions/9008847/what-is-difference-between-p-and-pp
require 'pp'
buffer = open('http://api.cryptocoincharts.info/tradingPair/eth_btc').read
# api_key = "FtHwuH8w1RDjQpOr0y0gF3AWm8sRsRzncK3hHh9"
result = JSON.parse(buffer)
puts result["markets"]
# result.each do |user|
# puts "#{user['id']}\t#{user['name']}\t#{user['email']}"
# puts "Registered: #{user['created_at']}\n\n"
# end
# my_hash = JSON.parse('{"hello": "goodbye"}')
# puts my_hash["hello"] => "goodbye"

With Net::HTTP:
require 'net/http'
uri = URI('http://example.com/index.html?count=10')
Net::HTTP.get(uri) # => String
Then you can do whatever you want with the data. If for example the API returns JSON, you can parse the String with Ruby's JSON module.

Related

Header information getting lost in POST response

In a ruby POST call I am expecting some custom header named 'Authentication-Token', which is received when called from any other REST client. But when called from ruby script I am getting all headers except this required header.
Below is the code
require 'net/http'
require 'json'
require 'uri'
uri = URI.parse('http://ashish-1:9090/csm/login')
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"username" => 'test', "password" => 'test'})
request.add_field("Authentication-Token", "")
request.add_field("Authorization", "")
request.add_field("Content-Type", "application/json")
response = http.request(request)
puts response
puts response.code
puts "Headers: #{response.to_hash}" #prints all headers except Authentication-Token
puts response["session-id"] # get printed
puts response["Authentication-Token"] # blank
Any idea what is missing?
Thanks,
Ashish

Post png image to pngcrush with Ruby

In ruby, I want to get the same result than the code below but without using curl:
curl_output = `curl -X POST -s --form "input=##{png_image_file};type=image/png" http://pngcrush.com/crush > #{compressed_png_file}`
I tried this:
#!/usr/bin/env ruby
require "net/http"
require "uri"
# Image to crush
png_image_path = "./media/images/foo.png"
# Crush with http://pngcrush.com/
png_compress_uri = URI.parse("http://pngcrush.com/crush")
png_image_data = File.read(png_image_path)
req = Net::HTTP.new(png_compress_uri.host, png_compress_uri.port)
headers = {"Content-Type" => "image/png" }
response = req.post(png_compress_uri.path, png_image_data, headers)
p response.body
# => "Input is empty, provide a PNG image."
The problem with your code is you do not send required parameter to the server ("input" for http://pngcrush.com/crush). This works for me:
require 'net/http'
require 'uri'
uri = URI.parse('http://pngcrush.com/crush')
form_data = [
['input', File.open('filename.png')]
]
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new uri
# prepare request parameters
request.set_form(form_data, 'multipart/form-data')
response = http.request(request)
# save crushed image
open('crushed.png', 'wb') do |file|
file.write(response.body)
end
But I suggest you to use RestClient. It encapsulates net/http with cool features like multipart form data and you need just a few lines of code to do the job:
require 'rest_client'
resp = RestClient.post('http://pngcrush.com/crush',
:input => File.new('filename.png'))
# save crushed image
open('crushed.png', 'wb') do |file|
file.write(resp)
end
Install it with gem install rest-client

Hash/string gets escaped

This is my hyperresource client:
require 'rubygems'
require 'hyperresource'
require 'json'
api = HyperResource.new(root: 'http://127.0.0.1:9393/todos',
headers: {'Accept' => 'application/vnd.127.0.0.1:9393/todos.v1+hal+json'})
string = '{"todo":{"title":"test"}}'
hash = JSON.parse(string)
api.post(hash)
puts hash
The hash output is: {"todo"=>{"title"=>"test"}}
At my Sinatra with Roar API I have this post function:
post "/todos" do
params.to_json
puts params
#todo = Todo.new(params[:todo])
if #todo.save
#todo.extend(TodoRepresenter)
#todo.to_json
else
puts 'FAIL'
end
end
My puts 'params' over here gets: {"{\"todo\":{\"title\":\"test\"}}"=>nil}
I found out, these are 'escaped strings' but I don't know where it goes wrong.
EDIT:
I checked my api with curl and postman google extension, both work fine. It's just hyperresource I guess
You are posting JSON, ergo you either need to register a Sinatra middleware that will automatically parse incoming JSON requests, or you need to do it yourself.
require 'rubygems'
require 'hyperresource'
require 'json'
api = HyperResource.new(root: 'http://127.0.0.1:9393/todos',
headers: {'Accept' => 'application/vnd.127.0.0.1:9393/todos.v1+hal+json'})
string = '{"todo":{"title":"test"}}'
hash = JSON.parse(string)
api.post({:data => hash})
puts hash
---
post "/todos" do
p = JSON.parse(params[:data])
puts p.inspect
#todo = Todo.new(p[:todo])
if #todo.save
#todo.extend(TodoRepresenter)
#todo.to_json
else
puts 'FAIL'
end
end
Should do what you need.

Ruby HTTP get with params

How can I send HTTP GET request with parameters via ruby?
I have tried a lot of examples but all of those failed.
I know this post is old but for the sake of those brought here by google, there is an easier way to encode your parameters in a URL safe manner. I'm not sure why I haven't seen this elsewhere as the method is documented on the Net::HTTP page. I have seen the method described by Arsen7 as the accepted answer on several other questions also.
Mentioned in the Net::HTTP documentation is URI.encode_www_form(params):
# Lets say we have a path and params that look like this:
path = "/search"
params = {q: => "answer"}
# Example 1: Replacing the #path_with_params method from Arsen7
def path_with_params(path, params)
encoded_params = URI.encode_www_form(params)
[path, encoded_params].join("?")
end
# Example 2: A shortcut for the entire example by Arsen7
uri = URI.parse("http://localhost.com" + path)
uri.query = URI.encode_www_form(params)
response = Net::HTTP.get_response(uri)
Which example you choose is very much dependent on your use case. In my current project I am using a method similar to the one recommended by Arsen7 along with the simpler #path_with_params method and without the block format.
# Simplified example implementation without response
# decoding or error handling.
require "net/http"
require "uri"
class Connection
VERB_MAP = {
:get => Net::HTTP::Get,
:post => Net::HTTP::Post,
:put => Net::HTTP::Put,
:delete => Net::HTTP::Delete
}
API_ENDPOINT = "http://dev.random.com"
attr_reader :http
def initialize(endpoint = API_ENDPOINT)
uri = URI.parse(endpoint)
#http = Net::HTTP.new(uri.host, uri.port)
end
def request(method, path, params)
case method
when :get
full_path = path_with_params(path, params)
request = VERB_MAP[method].new(full_path)
else
request = VERB_MAP[method].new(path)
request.set_form_data(params)
end
http.request(request)
end
private
def path_with_params(path, params)
encoded_params = URI.encode_www_form(params)
[path, encoded_params].join("?")
end
end
con = Connection.new
con.request(:post, "/account", {:email => "test#test.com"})
=> #<Net::HTTPCreated 201 Created readbody=true>
I assume that you understand the examples on the Net::HTTP documentation page but you do not know how to pass parameters to the GET request.
You just append the parameters to the requested address, in exactly the same way you type such address in the browser:
require 'net/http'
res = Net::HTTP.start('localhost', 3000) do |http|
http.get('/users?id=1')
end
puts res.body
If you need some generic way to build the parameters string from a hash, you may create a helper like this:
require 'cgi'
def path_with_params(page, params)
return page if params.empty?
page + "?" + params.map {|k,v| CGI.escape(k.to_s)+'='+CGI.escape(v.to_s) }.join("&")
end
path_with_params("/users", :id => 1, :name => "John&Sons")
# => "/users?name=John%26Sons&id=1"

Get file size before downloading & counting how much already downloaded (http+ruby)

Can anybody help me to
get the file size before I start downloading
display how much % was already downloaded
.
require 'net/http'
require 'uri'
url = "http://www.onalllevels.com/2009-12-02TheYangShow_Squidoo_Part 1.flv"
url_base = url.split('/')[2]
url_path = '/'+url.split('/')[3..-1].join('/')
Net::HTTP.start(url_base) do |http|
resp = http.get(URI.escape(url_path))
open("test.file", "wb") do |file|
file.write(resp.body)
end
end
puts "Done."
Use the request_head method. Like this
response = http.request_head('http://www.example.com/remote-file.ext')
file_size = response['content-length']
The file_size will be in bytes.
Follow these two links for more info.
http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTP.html#M000695
http://curl.haxx.se/mail/archive-2002-07/0070.html
so I made it work even with the progress bar ....
require 'net/http'
require 'uri'
require 'progressbar'
url = "url with some file"
url_base = url.split('/')[2]
url_path = '/'+url.split('/')[3..-1].join('/')
#counter = 0
Net::HTTP.start(url_base) do |http|
response = http.request_head(URI.escape(url_path))
ProgressBar#format_arguments=[:title, :percentage, :bar, :stat_for_file_transfer]
pbar = ProgressBar.new("file name:", response['content-length'].to_i)
File.open("test.file", 'w') {|f|
http.get(URI.escape(url_path)) do |str|
f.write str
#counter += str.length
pbar.set(#counter)
end
}
end
pbar.finish
puts "Done."
The file size is available in the HTTP Content-Length response header. If it is not present, you can't do anything. To calculate the %, just do the primary school math like (part/total * 100).
Here the full code to get file details before download
require 'net/http'
response = nil
uri = URI('http://hero.com/abc.mp4')
Net::HTTP.start(uri.host, uri.port) do |http|
response = http.head(uri)
end
response.header.each_header {|key,value| puts "#{key} = #{value}" }

Resources