Ruby Rest client POST, how to send headers - ruby-on-rails

Ruby rest client is not able to send headers, my java service is not able to read headers when I trigger post request from ruby as below. My Service layers throws error Header companyID is missing. When run the same http request in Postman it works.
response = RestClient::Request.new({
method: :post,
url: 'https://example.com/submitForm',
headers:{content_type: 'application/x-www-form-urlencoded',
companyID:'Company1',
Authorization:'Basic HELLO1234'},
payload: { data: str_res}
}).execute do |response, request, result|
case response.code
when 400
[ :error, JSON.parse(response.to_str) ]
when 200
[ :success, JSON.parse(response.to_str) ]
puts request.headers
else
fail "Invalid response #{response.to_str} received."
end
end
Here is postman code that works. Need similar in Ruby Rest, pls advise.
POST /submitForm HTTP/1.1
Host: example.com
companyID: Company1
Authorization: Basic HELLO1234
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: 528cafa1-2b5d-13a1-f227-bfe0171a9437
data=My Own data

Below worked. Looks like headers should be in same line.
payloadString = "data=My Own data"
response = RestClient::Request.new({
method: :post,
url: 'https://example.com/submitForm',
payload: payloadString,
headers: {content_type: 'application/x-www-form-urlencoded', companyID:'Company1', Authorization:'Basic HELLO1234'}
}).execute do |response, request, result|
case response.code
when 400
[ :error, JSON.parse(response.to_str) ]
when 200
[ :success, JSON.parse(response.to_str) ]
else
fail "Invalid response #{response.to_str} received."
end
end

Try using the RestClient post method:
result = RestClient.post(
'https://example.com/submitForm',
payload,
{
content_type: 'application/x-www-form-urlencoded',
companyID: 'Company1',
Authorization: 'Basic HELLO1234'
}
)
Payload in this instance is a string, so you'll need to figure out the appropriate structure for application/x-www-form-urlencoded. For example:
payload.to_json => '{"data": "str_res"}'

Related

Stubbed request not allowing http connections (Real HTTP connections are disabled.)

I am trying to stub a POST request to an external API. The spec test does not replace the ENV variable with my fake one and goes to my local env (localhost:3000) in the stub request returning this error:
Failure/Error: response = http.request(request)
WebMock::NetConnectNotAllowedError:
Real HTTP connections are disabled. Unregistered request: POST http://localhost:3000/Target with body '{"name":"Wayfarer"}' with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}
You can stub this request with the following snippet:
stub_request(:post, "http://localhost:3000/Target").
with(
body: "{\"name\":\"Wayfarer\"}",
headers: {
'Accept'=>'*/*',
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
'User-Agent'=>'Ruby'
}).
to_return(status: 200, body: "", headers: {})
My test is:
let!(:user) { create(:user, target: 'Wayfarer') }
before(:each) do
allow(ENV).to receive(:fetch).with('API_METADATA_URL').and_return('http://example.com')
end
describe '#create_target' do
context 'successful API request to create target' do
it 'sends data to API and sets response instance variables' do
target = user.target
stub_request(:post, 'http://example.com/Target').with(
headers: {
},
body: '{
"name": "Wayfarer"
}'
).to_return(
status: 200,
body: '{"id": "uuid",' \
'"name": "Wayfarer",' \
'"created_at": 00000,' \
'"updated_at": 00000}'
)
api_client = ApiClient.new
api_client.create_target(target)
expect(api_client.response_status).to eq(200)
expect(api_client.response_body).to eq(
{
'id' => 'uuid',
'name' => 'Wayfarer',
'created_at' => 00000,
'updated_at' => 00000
}
)
end
end
end
It doesn't even reach the test, instead it seems to run the ApiClient as is including using my local environment variable (as stated above).
I ended up needing a separate .env file for tests (.env.test.local) for the API_METADATA_URL for a url that did not throw the error.

How to convert a CURL request to Ruby Gem HTTPClient

I am trying to convert this CURL request:
curl \
-F 'slideshow_spec={
"images_urls": [
"<IMAGE_URL_1>",
"<IMAGE_URL_2>",
"<IMAGE_URL_3>"
],
"duration_ms": 2000,
"transition_ms": 200
}' \
-F 'access_token=<ACCESS_TOKEN>' \
https://google.com
To a HTTPClient request but all my attempts results in 400 Bad Request. Here's what I've tried:
payload = {
"images_urls": [
"https://cdn-m2.esoftsystems.com/10100028/TAASTRUP%40DANBOLIG.DK/10106239925/160596797/BEST_FIT/1542/1024/IMG_5511.jpg",
"https://cdn-m2.esoftsystems.com/10100028/TAASTRUP%40DANBOLIG.DK/10106239925/160596797/BEST_FIT/1542/1024/IMG_5511.jpg",
"https://cdn-m2.esoftsystems.com/10100028/TAASTRUP%40DANBOLIG.DK/10106239925/160596797/BEST_FIT/1542/1024/IMG_5511.jpg"
],
"duration_ms": 2000,
"transition_ms": 200
}
response = RestClient.post url, {slideshow_spec: payload.to_json, multipart: true, access_token: access_token}
Any ideas?
Your requests are not equivalent. I guess you are mixing JSON, Multipart and x-www-form-urlencoded formats here.
RestClient supports all three formats (examples taken from https://github.com/rest-client/rest-client/blob/master/README.md)
# POST JSON
RestClient.post "http://example.com/resource", {'x' => 1}.to_json, {content_type: :json, accept: :json}
# POST Multipart
# Usually not needed if you don't want to upload a file
RestClient.post '/data', {:foo => 'bar', :multipart => true}
# POST x-www-form-urlencoded
RestClient.post('https://httpbin.org/post', {foo: 'bar', baz: 'qux'})
Looks like your curl sample uses application/x-www-form-urlencoded, while your Ruby sample uses multipart/form-data.
For some background information, check
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
https://dev.to/sidthesloth92/understanding-html-form-encoding-url-encoded-and-multipart-forms-3lpa

Convert curl (with --data-urlencode) to ruby

I am trying to convert the following curl command to ruby using net/http but I haven't figured out how to pass in the --data-urlencode script#files/jql/events.js part of the command.
curl https://mixpanel.com/api/2.0/jql -u <apikey>: --data-urlencode script#files/jql/events.js
Using net/http I had the following...
uri = URI.parse("https://mixpanel.com/api/2.0/jql")
request = Net::HTTP::Get.new(uri)
request.basic_auth("<apikey>", "")
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
Is there anyway to do this? If not within net/http then maybe using another gem?
Mixpanel has it's official ruby gem
I didn't actually work with it, but I assume it have all needed methods.
But if you don't like to use it, you may use Faraday an awesome HTTP client library for Ruby.
I made a simple example with it. Please have a look:
class MixpanelClient
def initialize(url = "https://mixpanel.com/api/2.0/jql", api_key = "ce08d087255d5ceec741819a57174ce5")
#url = url
#api_key = api_key
end
def query_data
File.read("#{Rails.root}/lib/qry.js")
end
def query_params
'{"from_date": "2016-01-01", "to_date": "2016-01-07"}'
end
def get_events
resp = Faraday.new(url: #url, ssl: { verify: false }) do |faraday|
faraday.request :url_encoded
faraday.response :logger
faraday.adapter Faraday.default_adapter
faraday.basic_auth(#api_key, "")
end.get do |req|
req.params['script'] = query_data
req.params['params'] = query_params
end
raise MixpanelError.new("Mixpanel error") unless resp.status == 200
JSON.parse(resp.body)
end
end
class MixpanelError < StandardError; end
Here is the result:
[1] pry(main)> m = MixpanelClient.new
=> #<MixpanelClient:0x007fc1442d53b8 #api_key="ce08d087255d5ceec741819a57174ce5", #url="https://mixpanel.com/api/2.0/jql">
[2] pry(main)> m.get_events
I, [2016-06-09T09:05:51.741825 #36920] INFO -- : get https://mixpanel.com/api/2.0/jql?params=%7B%22from_date%22%3A+%222016-01-01%22%2C+%22to_date%22%3A+%222016-01-07%22%7D&script=function+main%28%29%7B+return+Events%28params%29.groupBy%28%5B%22name%22%5D%2C+mixpanel.reducer.count%28%29%29+%7D
D, [2016-06-09T09:05:51.741912 #36920] DEBUG -- request: Authorization: "Basic Y2UwOGQwODcyNTVkNWNlZWM3NDE4MTlhNTcxNzRjZTU6"
User-Agent: "Faraday v0.9.2"
I, [2016-06-09T09:05:52.773172 #36920] INFO -- Status: 200
D, [2016-06-09T09:05:52.773245 #36920] DEBUG -- response: server: "nginx/1.9.12"
date: "Thu, 09 Jun 2016 03:05:52 GMT"
content-type: "application/json"
transfer-encoding: "chunked"
connection: "close"
vary: "Accept-Encoding"
cache-control: "no-cache, no-store"
access-control-allow-methods: "GET, POST, OPTIONS"
access-control-allow-headers: "X-PINGOTHER,Content-Type,MaxDataServiceVersion,DataServiceVersion,Authorization,X-Requested-With,If-Modified-Since"
=> [{"key"=>["Change Plan"], "value"=>186}, {"key"=>["View Blog"], "value"=>278}, {"key"=>["View Landing Page"], "value"=>1088}, {"key"=>["login"], "value"=>1241}, {"key"=>["purchase"], "value"=>359}, {"key"=>["signup"], "value"=>116}]
A set ssl: {verufy: false} because Faraday need addtitional workaround to work with ssl certificates: https://github.com/lostisland/faraday/wiki/Setting-up-SSL-certificates

Rails RestClient POST request failing with "400 Bad Request"

Looking at the docs there aren't any good examples of how to make a POST request. I need to make a POST request with a auth_token parameter and get a response back:
response = RestClient::Request.execute(method: :post,
url: 'http://api.example.com/starthere',
payload: '{"auth_token" : "my_token"}',
headers: {"Content-Type" => "text/plain"}
)
400 bad request error:
RestClient::BadRequest: 400 Bad Request
from /Users/me/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rest-client-1.8.0/lib/restclient/abstract_response.rb:74:in `return!'
from /Users/me/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rest-client-1.8.0/lib/restclient/request.rb:495:in `process_result'
from /Users/me/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rest-client-1.8.0/lib/me/request.rb:421:in `block in transmit'
Any good examples how to make a POST request using RestClient?
EDIT:
This is how I make the request in the model:
def start
response = RestClient::Request.execute(method: :post,
url: 'http://api.example.com/starthere',
payload: '{"auth_token" : "my_token"}',
headers: {"Content-Type" => "text/plain"}
)
puts response
end
Try using a hash like this:
def start
url= 'http://api.example.com/starthere'
params = {auth_token: 'my_token'}.to_json
response = RestClient.post url, params
puts response
end
If you just want to replicate the curl request:
response = RestClient::Request.execute(method: :post, url: 'http://api.example.com/starthere', payload: {"auth_token" => "my_token"})
Both Curl and RestClient defaults to the same content type (application/x-www-form-urlencoded) when posting data the this format.
In case you land here having the same Issue, Just know that this is a common error that happens when your environment variables are not "set".
I put this in quotes because you might have set it but not available in the current terminal session!
You can check if the ENV KEY is available with:
printenv <yourenvkey>
if you get nothing then it means you need to re-add it or just put it in your bash files
FYI: Putting my ENV variables in my ~/.bash_profile fixed it

How to send data in a post request with RestClient

I'm trying to mimic a curl request using the RestClient Ruby gem, and so far, I've been having a lot of trouble trying to send in a payload. My curl request looks something like this
curl URL -X POST -u API_KEY -d '{"param_1": "1"}'
I've been trying to replicate this with RestClient using something like this:
RestClient::Request.execute(method: :post, url: URL, user: API_KEY, payload: {"param_1" => "1"})
Alas, I keep getting 400 - Bad Requests errors when doing this. Am I sending data over the wrong way? Should I be using something other than payload?
Change:
payload: {"param_1" => "1"})
To:
payload: '{"param_1": "1"})'
Also, specify the headers.
So, it becomes:
RestClient::Request.execute(method: :post,
url: 'your_url',
user: 'API_KEY',
payload: '{"param_1": "1"}',
headers: {"Content-Type" => "application/json"}
)
Just Change:
payload: {"param_1" => "1"}
To:
payload: {"param_1" => "1"}.to_json
So, then it becomes:
RestClient::Request.execute(method: :post,
url: 'your_url',
user: 'API_KEY',
payload: {"param_1" => "1"}.to_json,
headers: {"Content-Type" => "application/json"}
)
Turns out I had to add an argument to specify that my data was in a JSON format. The correct answer was something like this:
RestClient::Request.execute(method: :post, url: URL, user: API_KEY, payload: '{"param_1": "1"}', headers: {"Content-Type" => "application/json"})

Resources