I am using RestClient in my rails app to send emails.
The following Curl command works:
curl -s "https://api:key-XYZ#api.mailgun.net/v2/sandbox30000.mailgun.org/messages" \
-F from='Mailgun Sandbox <postmaster#sandbox30000.mailgun.org>' \
-F to='me <my-email-id#gmail.com>'\
-F subject='Hello XYZ' \
-F text='Congratulations, you just sent an email with Mailgun! You are truly awesome!'
But when I try the same using RestClient, I get the following error message:
error response !!{
"message": "'from' parameter is missing"
}
error message !!400 Bad Request
RestClient call:
RestClient::Request.execute(
:url => "https://api:key-XYZ#api.mailgun.net/v2/sandbox0000.mailgun.org/messages",
:method => :post,
:from => 'Mailgun Sandbox <postmaster#sandbox30000.mailgun.org>',
:sender => 'Mailgun Sandbox <postmaster#sandbox30000.mailgun.org>',
:to => "my-email-id#gmail.com",
:subject => "Hello XYZ",
:text => "Text body",
:"h:X-My-Header" => "www/mailgun-email-send",
:verify_ssl => false)
When you use Request.execute with multiple payload arguments and header(s) you will need to tell RestClient what type of data it is.
You need to these three fixes to get the equivalent curl-request with RestClient.
Group all post fields into a payload hash
Add the single header into a header hash
Tell RestClient that the payload should be sent as multipart.
The changed request:
RestClient::Request.execute(
:url => "https://api:key-XYZ#api.mailgun.net/v2/sandbox0000.mailgun.org/messages",
:method => :post,
:payload => {
:from => 'Mailgun Sandbox <postmaster#sandbox30000.mailgun.org>',
:sender => 'Mailgun Sandbox <postmaster#sandbox30000.mailgun.org>',
:to => "my-email-id#gmail.com",
:subject => "Hello XYZ",
:text => "Text body",
:multipart => true
},
:headers => {
:"h:X-My-Header" => "www/mailgun-email-send"
},
:verify_ssl => false
)
Related
I am writin specs for my gem and I am using webmock to mock http requests. But i keep on getting this weird error.
Here is my specs code
require 'spec_helper'
describe 'Generator::Exotel' do
describe '#success' do
let(:resps) { {"Status"=>"200", "Message"=>"Success"} }
before do
stub_request(:post, "https://test_sid:test_token#twilix.exotel.in/v1/Accounts/#{Generator::configuration.sid}/Sms/send").
with(:body => {:To => 1234, :Body => "test sms"}, :headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(:body => resps.to_json, :headers => {})
end
it 'returns response object for success' do
response = Generator::Exotel.send(:to => 1234, :body => "test sms")
expect(response.to_json).to eq (resps.to_json)
end
end
describe '#failure' do
let(:resp) { {"Status"=>"401", "Message"=>"Not Authenticated"} }
before do
stub_request(:post, "https://test_sid:test_token#twilix.exotel.in/v1/Accounts/#{Generator::configuration.sid}/Sms/send").
with(:body => {:To => 1234, :Body => "test sms"}, :headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(:body=> resp.to_json, :headers => {})
end
it 'returns response object for failure' do
response = Generator::Exotel.send(:to => 1234, :body => "test sms")
expect(response.to_json).to eq (resp.to_json)
end
end
end
Whenever i run rspec, i am getting this following error
Generator::Exotel #success returns response object for success
Failure/Error: response = self.class.post("/#{Generator::configuration.sid}/Sms/send", {:body => params, :basic_auth => auth })
WebMock::NetConnectNotAllowedError:
Real HTTP connections are disabled. Unregistered request: POST https://twilix.exotel.in/v1/Accounts/test_sid/Sms/send with body 'To=1234&Body=test%20sms' with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Basic dGVzdF9zaWQ6dGVzdF90b2tlbg==', 'User-Agent'=>'Ruby'}
You can stub this request with the following snippet:
stub_request(:post, "https://twilix.exotel.in/v1/Accounts/test_sid/Sms/send").
with(:body => "To=1234&Body=test%20sms",
:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Basic dGVzdF9zaWQ6dGVzdF90b2tlbg==', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "", :headers => {})
registered request stubs:
stub_request(:post, "https://test_sid:test_token#twilix.exotel.in/v1/Accounts/test_sid/Sms/send").
with(:body => {"Body"=>"test sms", "To"=>1234},
:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'})
============================================================
I have googled a lot and found some solutions, i.e,
Solution 1
Relish Documentation
“WebMock::NetConnectNotAllowedError”
Also i had a look at this post , But in vain.
Also i tried using WebMock.disable_net_connect!(:allow_localhost => true)
but got the same result. Anyone know what am i doing wrong? I am really new to ruby and for first time i am writing specs and its really confusing me.
You cannot make external http requests with webmock, as rightly said by various posts that you mentioned. I notice your stubbed urls have interpolated variables in them ie "https://test_sid:test_token#twilix.exotel.in/v1/Accounts/#{Generator::configuration.sid}/Sms/send". You need to:
Make sure Generator::configuration.sid is accessible within the specs
If it's not accessible then just return a plain url which is perfectly fine
I made a post request with RestClient::Request.execute, which works, but sometimes it ended with a 422(Unprocessable Entity).
Afterwards I tried out RestClient.post which didn´t gave me the 422 and worked all the time like a charm.
What is the difference between the two Calls?
I know that with RestClient::Request there are more possibilities for using parameters than with RestClient.post. I do not understand why i get a 422 with one method and not with the other.
Here I used json:
response = RestClient::Request.execute(
:method => :post,
:url => 'http://localhost:3000',
:timeout => 30,
:open_timeout => 2,
:payload => payload.to_json,
:headers => {
:content_type => :json,
:accept => :json
}
)
vs.
response = RestClient.post('http://localhost:3000',
:param1 => 'abc',
:param2 => "def")
They are the same - RestClient.post is a syntax sugar for execute, see restclient's sources, restclient.rb:
def self.post(url, payload, headers={}, &block)
Request.execute(:method => :post,
:url => url,
:payload => payload,
:headers => headers, &block)
end
The 422 is caused by something else
I am trying to send a post request to a separate app where I need to send a matching signature that is not json encoded and the data, which is json encoded. I keep getting errors when I try to do this, so I'm just not understanding how to format it, and I can't find any examples on SO or their documentation (or anywhere else on the web).
signature = create_signature
result = HTTParty.post("weburl.com/file/to/post_to.php",
:body => {[ signature,
:data => { :timestamp => #message.created_at,
:url => company.request_host,
:name => #message.name,
:email => #message.email,
:phone => #message.phone,
:product => #message.service,
:comments => #message.message
}.to_json
]},
:headers => { 'Content-Type' => 'application/x-www-form-urlencoded' },
:verify => false )
The error I'm getting currently is syntax error, unexpected '}', expecting => ]}, ^
I've also tried without the arrays, without the data array, etc.
How do I format this to properly submit this info?
I think you need to move your .to_json to the end of the object.
:body => {[ signature,
:data => { :timestamp => #message.created_at,
:url => company.request_host,
:name => #message.name,
:email => #message.email,
:phone => #message.phone,
:product => #message.service,
:comments => #message.message
}
].to_json},
I've tested my controller and have got strange errors like this:
expected: ("376")
got: (376)
Please stub a default value first if message might be received with other args as well.
This is my spec:
it 'should send confirm-email if information is good' do
sign_in user
allow(Order).to receive(:find).with(order.id.to_s).and_return(order)
allow(order).to receive(:finalize) {order}
allow(order.errors).to receive(:empty?) {true}
expect(OrderMailer).to receive_message_chain(:send_finish_notification, :deliver)
patch :save_order, {:id => order.id , :order => {:street_address => 'Baker street', :apt => '123#', :zip_id => zip.id, :frequency_id => frequency.id, :amount_per_hour => '5',
:extras_ids => '', :phone_number => '3213', :credit_card_number => '4242424242424242', :credit_card_cvv => '777',
:credit_card_expiration => '12/20', :source_information => ''}}
end
And I've got this error in some logically close specs. But some tests passes, like this one:
it 'should not update user data if order errors is not empty' do
sign_in user
allow(Order).to receive(:find).with(order.id.to_s).and_return(order)
allow(order).to receive(:finalize) {order}
allow(order.errors).to receive(:empty?) {false}
expect(User).to_not receive(:update_user_data)
patch :save_order, {:id => order.id, :order => {:street_address => 'Baker street', :apt => '123#', :zip_id => zip.id, :frequency_id => frequency.id, :amount_per_hour => '5',
:extras_ids => '', :phone_number => '3213', :credit_card_number => '4242424242424242', :credit_card_cvv => '777',
:credit_card_expiration => '12/20', :source_information => ''}}
end
to_s or to_i doesn't help. The error line in controller -
#order = Order.find(params[:id]
So what could be in that case ? 'Cause it looks like some specs passes, but similar to them don't. Any suggestions ?
I have been using a RestClient request as such:
response = RestClient.post server_url, post_params, accept: :json
Which has been working fine. But I need to increase the timeout as it's not completing every now and then while the server is performing the upload.
I have researched and found that the only solution is to change the syntax to something like:
response = RestClient::Request.execute(:method => :post, :url => server_url, post_params, :timeout => 9000000000)
however, I don't seem to be able to pass the hashmap of parameters ('post_params') like i was able to in the previous call. how should I write the request so that 'post_params' is included. It's a complex hashmap, so i can't augment it or get rid of it.
Help is much appreciated.
The data you send is called a payload, so you need do specify it as payload:
response = RestClient::Request.execute(:method => :post, :url => server_url, :payload => post_params, :timeout => 9000000, :headers => {:accept => :json})
Also, you may want to use a shorter timeout, otherwise there is a chance you get a Errno::EINVAL: Invalid argument.
the data you send is in payload when we try to use rest_client.post or any method like get,put what rest_client do is
def self.post(url, payload, headers={}, &block)
Request.execute(:method => :post, :url => url, :payload => payload,
:headers => headers, &block)
end
so like we want to execute
response = RestClient.post api_url,
{:file => file, :multipart => true },
{ :params =>{:foo => 'foo'} #query params
so in the execute command will take take {:file => file, :multipart => true } as payload and { :params =>{:foo => 'foo' } } as header so
for passing all these you need
response= RestClient::Request.execute(:method => :post,
:url => api_url,
:payload => {:file => file, :multipart => true },
:headers => { :params =>{:foo => 'foo'}},
:timeout => 90000000)
this should do