How to Send HTTP_REQUEST without encoding? - ruby

I want to send a request without encoding the params. Because my API is expecting the params as auth_token but while sending request it got encoded to auth%5Ftoken. Because of this its throwing error. Please help me to send request without encoding. I am using gym Typhoeus to send http requests.
MY CODE:
data = {"auth_token"=>"abcd" ,"employee" => {"method" => "add_employee"}}
header = { "Content-Type" => "application/json","Accept"=>"application/json"}
request = Typhoeus::Request.post("www.example.com",:body=> data.to_json,:headers => header)

Related

Ruby GET NET HTTP request does not work with AUTHORIZATION and ACCEPT when passed in a header

I've been using the code below to call a third party API . This code works fine (i've changed the url and the credentials but the structure of the code is the same) :
require 'base64'
require 'httparty'
require 'json'
######################################################################
# Get the token first
######################################################################
consumer_key = "my_key"
consumer_secret = "my_secret"
credentials = Base64.encode64("#{consumer_key}:#{consumer_secret}").gsub("\n", '')
url = "https://mysite/token"
body = "grant_type=client_credentials"
headers = {
"Authorization" => "Basic #{credentials}",
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
}
r = HTTParty.post(url, body: body, headers: headers)
bearer_token = JSON.parse(r.body)['access_token']
######################################################################
# Use the token in a call as authorisation header
######################################################################
api_url = "https://apisite/the_value_i_am_looking_for_in_the_api"
url = URI.parse(api_url)
req = Net::HTTP.new(url.host, url.port)
req.use_ssl = true
# If we are just passing a key that doesn't need to be in the token format
headers = {
'Authorization' => "Bearer #{bearer_token}"
}
# Get the response back (he data is in the response body: resp.body )
resp = req.get(url, headers)
My issue is that the API providers have changed their API so you now need to pass an "accept" into the call via the header. I used POSTMAN to make the call, added the accept to the header and was able to get it working without issue. So far so good.
I then changed my ruby code to extend the headers section to include the accept, using the code below:
headers = {
'Authorization' => "Bearer #{bearer_token}",
'Accept' => 'application/vnd.bluebadge-api.v1+json'
}
I've not added an accept to a header before so I may have gotten the syntax wrong.
However, this returns an unauthorised 401 response code:
#<Net::HTTPUnauthorized 401 Unauthorized readbody=true>
I thought I might have the credentials wrong so remove the accept, try again and this changes to a 406 response code:
#<Net::HTTPNotAcceptable 406 Not Acceptable readbody=true>
If I examine the response I get the message I would expect that the accept header is not the supported version. So I know the credentials are correct (and the fact they match the postman credentials which works):
"{\"apiVersion\": \"1\",\"context\": null,\"id\": null,\"method\": null,\"error\": {\"code\": null,\"message\": null,\"reason\": \"Accept header version is not a currently supported version.\",\"errors\": null}}\n"
So I know all my credentials are correct because I've copied them into the postman request which works with no errors. The value for the accept header is correct because I copied that from a working postman request too.
I am at a loss for why this wouldn't work.
I've looked through the NET HTTP library and cant find anything to help me there. I've seen a couple of posts elsewhere which I've tried and they haven't worked either.
I appreciate any help in trying to solve this.
Found the problem. I was using the credentials from the production environment to get the token then trying to query the test environment API. In my defence they look very similar (only 3 characters different). I think I had a case of the code blindness.
The code I posted does work when I put the correct URL for the environments.
I also found that I could use this:
uri = URI.parse("https://myapi/some_text")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
request["Authorization"] = "Bearer #{bearer_token}"
request["Accept"] = "application/vnd.bluebadge-api.v1+json"
response = http.request(request)
Or using HTTParty like this:
response = HTTParty.get('https://myapi/some_text', {
headers: {"Authorization" => "Bearer #{bearer_token}", "Accept" => "application/vnd.bluebadge-api.v1+json" }
})
I would prefer the format of my orginal code or the HTTparty code because it is easy to see from the code that you're passing headers. Hopefully this will help others to double check their authorization credentials...

Failed authentication with Ruby HTTPClient

I have this very simple Ruby code which makes Ruby POST request.
For some reason it creates 2 requests - one authentication error and one successful request:
def execute
request = HTTPClient.new()
request.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
request.set_auth('https://test.net/api', 'user', 'pass')
request_body = File.read("requests/xml/req.xml")
response = request.post('https://test.net/api', request_body, {'Content-Type' => 'application/xml', 'cache-control' => 'no-cache'}).body
puts 'called'
end
I suppose that some configuration if missing for HTTPClient?
Can you advise how I can fix this?
This is an expected behavior. The client won't send the credentials unless they are required. When the client gets a 401 status code then it sends the request again but now with the credentials.
You can force some clients to send the credentials on the first request.
Ruby's HTTPClient has a force_basic_auth that does that.

MultiJson::LoadError: 795: unexpected token when trying to parse incoming body request

I'm losing my sanity trying to parse an incoming request on a Sinatra app.
This is my spec
payload = File.read("./spec/support/fixtures/payload.json")
post "/api/v1/verify_payload", { :payload => payload }
last_response.body.must_equal payload
where is simply spec/support/fixtures/payload.json
{"ref":"refs/heads/master"}
My route looks like
post '/verify_payload' do
params = MultiJson.load(request.body.read, symbolize_keys: true)
params[:payload]
end
And running the spec I get the following error:
MultiJson::LoadError: 795: unexpected token at 'payload=%7B%22ref%22%3A%22refs%2Fheads%2Fmaster%22%7D'
I have tried to parse the body request in different ways without luck.
How can I make the request valid JSON?
THANKS
If you want to send a JSON-encoded POST body, you have to set the Content-Type header to application/json. With Rack::Test, you should be able to do this:
post "/api/v1/verify_payload", payload, 'CONTENT_TYPE' => 'application/json'
Alternatively:
header 'Content-Type' => 'application/json'
post '/api/v1/verify_payload'
More info here: http://www.sinatrarb.com/testing.html
The problem it is that you are passing a ruby hash, that is not well formated, you should pass a json object.
Something like this, should work:
post "/api/v1/verify_payload", { :payload => payload.to_json }

What is Net::HTTP doing differently than executing curl in ruby?

I have methods that GETs a resource from an external Rails server via JSON. One uses the net/http library, the other executes curl. They respond differently.
If I use net/http
def get_via_nethttp(endpoint, user, password, id)
uri = URI.parse("#{endpoint}/items/#{id}.json")
http = Net::HTTP.new(uri.host, uri.port)
headers = {
'Content-Type' => 'application/json',
'Accept-Encoding' => 'gzip,deflate',
'Accept' => 'application/json'
}
request = Net::HTTP::Get.new(uri.request_uri, headers)
request.basic_auth(user, password)
http.request(request)
end
then the return code is ASCII-8Bit encoded. Here's a snippet:
\x1F\x8B\b\x00\x00\x00\x00\x00\x00\x03\xBDWmo\xE28\x10\xFE+Vv\xA5...
However, if I use curl
def get_via_curl(endpoint, user, password, id)
%x(curl -u #{user}:#{password} #{endpoint}/items/#{id}.json)
end
then a JSON string returns
"{\"id\":1234,\"title\":\"Foo\"}"
I've tried numerous ways to decode the output of net/http to no avail. In the end, I just want the JSON string, so I ended up going with curl. What's the difference that's causing this?
Setting in headers 'Accept-Encoding' => 'gzip,deflate' can result server sending you a chunked response. Just remove it.

View request text before sending

I'm using Net::HTTP to make a POST request:
uri = 'service.example.com'
https = Net::HTTP.new(uri)
https.use_ssl = true
path = "/service_action"
data = request_body_obj.to_json
response = https.post(path, data, {'Content-Type' => 'application/json'})
My request is timing out for some reason. To debug why, I'd like to see the text of the request body and headers of my request. Is there a way to do that?

Resources