How to get api data using api keys in httparty ruby - ruby

i have been trying to get the api data using httparty and been doing it like this
require 'httparty'
doc = HTTParty.get('http://ip-api.com/php/105.49.23.183')
puts doc['status']
The api response is
a:14:{s:6:"status";s:7:"success";s:7:"country";s:5:"Kenya";s:11:"countryCode";s:2:"KE";s:6:"region";s:2:"30";s:10:"regionName";s:16:"Nairobi Province";s:4:"city";s:7:"Nairobi";s:3:"zip";s:5:"09831";s:3:"lat";d:-1.25909;s:3:"lon";d:36.7858;s:8:"timezone";s:14:"Africa/Nairobi";s:3:"isp";s:17:"Safaricom Limited";s:3:"org";s:3:"SFC";s:2:"as";s:25:"AS33771 Safaricom Limited";s:5:"query";s:13:"105.49.23.183";}
but the output when i run my script is just
status
but i need it to return the data responding to the status key which is success. I can't figure it out how to do this. Initially in python this method works but ruby is different

Just use the JSON formatted API endpoint:
require 'httparty'
doc = HTTParty.get('http://ip-api.com/json/105.49.23.183')
puts doc['status']
#=> "success"
Notice the json instead of the php in the URL path. The serialized PHP endpoint is deprecated anyway.

Related

Ruby Sinatra - Range Error with large-ish json payload in post request

I am building a small Sinatra API that will run some calculations and store results on the server. The POST route requires a JSON payload. The JSON payload is a combination of floats, arrays of floats and base64 encoded data.
This is the route
post '/calc' do
rad_data = JSON.parse(request.body.read)
# Perform calculations
end
Everything works fine when the json is around 2.8MB, but when the size gets to 3.9MB I receive the error
2021-11-20 17:33:43 +0000 Rack app ("POST /calc" - (78.110.164.58)): #<RangeError: RangeError>
(It is also weird that 78.110.164.58 is not the ip address of the machine and i have no idea where it comes from.)
The structure of the payload is exactly the same. The larger one has simply longer arrays. Also, if I load the file directly on the server everything works, so it is not a problem with the json content.
Based on this answer I have added the key_space_limit to the beginning of the app, but it makes no difference.
require 'sinatra'
require 'sinatra/reloader'
require 'rack'
if Rack::Utils.respond_to?("key_space_limit=")
puts "Yes"
Rack::Utils.key_space_limit = 2**64
end
Just in case it helps, I send my request with Ruby rest-client
RestClient.post(uri_post, JSON.dump(rad_data))

Send a html string in multipart post call using rest client ruby gem

I am using RestClient ruby gem to make a multipart call like below and it works fine
RestClient.post 'my_url', {:myfile => File.new("/path/to/image.jpg", 'rb') ,:multipart => true}
In second case I have a html string like this "<html> <title>sometitle</title></html>"
I want to post this html as a file in above call. Is it possible to post the above html in the call below.
One option is to create a new file with above html content and use that but I don't want to do this. I am new to ruby . Can anyone help.

How to read POST data in rack request

When I run the curl command
curl -v -H "Content-type: application/json" -X POST -d '{"name":"abc", "id":"12", "subject":"my subject"}' http://localhost:9292
to send a POST request with data to my Rack application, my code prints out {}. That is coming from puts req.POST() in the code below.
Why does it print out {} instead of the POST data? And how do I correctly access the POST data in my Rack application?
require 'json'
class Greeter
def call(env)
req = Rack::Request.new(env)
if req.post?
puts req.POST()
end
[200, {"Content-Type" => "application/json"}, [{x:"Hello World!"}.to_json]]
end
end
run Greeter.new
From reading the docs for POST, looks like it is giving you parsed data based on other content types. If you want to process "application/json", you probably need to
JSON.parse( req.body.read )
instead. To check this, try
puts req.body.read
where you currently have puts req.POST.
req.body is an I/O object, not a string. See the body documentation and view the source. You can see that this is in fact the same as mudasobwa's answer.
Note that other code in a Rack application may expect to read the same I/O, such as the param parsers in Sinatra or Rails. To ensure that they see the same data and not get an error, you may want to call req.body.rewind, possibly both before and after reading the request body in your code. However, if you are in such a situation, you might instead consider whether your framework has options to process JSON directly via some option on the controller or request content-type handler declaration etc - most likely there will be an option to handle this kind of request within the framework.
Try:
env['rack.input'].read
I found it in "How to receive a JSON object with Rack" and, though it still sounds weird to me, it likely works.
You can try:
req.params
Hope this can help you.

How to send DELETE request with body using ruby gem?

I am communicating with API that requires DELETE request with JSON body. This works on console:
curl -XDELETE http://api.com/endpoint_path/rest_resource
-d '{"items":[{"type":"type1","item_id":"item1"}]}'
It seems that most gems for making HTTP requests don't support DELETE request with body (I tried RestClient and Curb). Is there a way to do it using some Ruby gem (preferably Curb) or Net::HTTP?
Here's one way using HTTParty:
HTTParty.delete("http://api.com/endpoint_path/rest_resource", {
:body => '{"items":[{"type":"type1","item_id":"item1"}]}'
})
it could be used her. This is ORM for api. https://github.com/remiprev/her
Example of usage:
RestResource.destroy_existing(id, body_params)
I also spent some time on this issue and #Casper's answer shed the light.
Seems to me that the key is to pass the body value as JSON string, which is not written in most of the documentations I found.
Here's another example using httpclient
require 'json'
body = { 'items': [{ 'type': 'type1', 'item_id': 'item1' }]}
HTTPClient.new.delete('http://api.com/endpoint_path/rest_resource', body.to_json)

Sinatra app that redirects POST/GET requests with parameters

I'm migrating servers but unfortunately the old server IP is hardcoded inside my iPhone app. Obviously I'm going to submit an update that sets the API endpoint to my new server, but in the meantime I need to setup an app on the old server that redirects all the requests to the new server. I've heard Sinatra would be perfect for this.
require 'sinatra'
get "/foo/bar" do
redirect "http://new-server.com/foo/bar", 303
end
post "/foo/bar" do
redirect "http://new-server.com/foo/bar", 303
end
The problem is that these do not forward the GET or POST parameters along with the request. I read on the Sinatra doc that you can do that by putting them in the URL directly (works for GET requests), or by setting session variables.
Is manually parsing and formatting the GET params to put them back into the redirect URL the only way to go for GET redirects? How are you supposed to forward POST parameters?
For GET requests, use request.fullpath or request.query_string. For POST request, use status code 307, so the subsequent request will be a POST with the same parameters.
helpers do
def new_url
"http://new-server.com" + request.fullpath
end
end
get "/foo/bar" do
redirect new_url
end
post "/foo/bar" do
redirect new_url, 307
end
I would overload the Hash class in lib/overload_hash.rb, like so:
class Hash
def to_url_params
elements = []
keys.size.times do |i|
elements << "#{keys[i]}=#{values[i]}"
end
elements.join('&')
end
end
EDIT (Better solution using net / http)
Place a require "lib/overload_hash", require "net/http" and require "uri" under require 'sinatra'. The following example can be translated into GET easily.
post '/foo/bar' do
uri = URI.parse("http://example.com/search")
response = Net::HTTP.post_form(uri, params.to_ur_params)
response
end

Resources