How to handle RestClient::ServerBrokeConnection - ruby-on-rails

I am using the latest version of rest-client gem and upon external access I see a lots of RestClient::ServerBrokeConnection errors, how should I handle this?
The following call fails
response = RestClient::Request.execute(method: :post, url: url, headers: headers, "Content-Type" => "application/x-www-form-urlencoded")

This error happens when the server broke the connection with the client. You can decide to retry the request or just bubble the error for the user to know about it and handle it.
Because how rest-client handles broken connections as shown here, all you can do is rescue from it
begin
response = RestClient::Request.execute(method: :post, url: url, headers: headers, "Content-Type" => "application/x-www-form-urlencoded")
rescue RestClient::ServerBrokeConnection
// retry or do something
end

Related

Can't verify CSRF token authenticity Rails/React

I have a react component in my rails app where I'm trying to use fetch() to send a POST to my rails app hosted on localhost, this gives me the error:
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
I'm using devise gem to handle user/registrations and logins.
I have tried to remove protect_from_forgery with: :exception
Here is the code for my fetch,
this.state.ids.sub_id});
fetch(POST_PATH, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: body
}).then(res => res.json()).then(console.log);
How can I get the csrf token and send it through the form so that it will pass?
Ideally I would like to just send it through the headers but I have no idea how to access the token.
The simplest way to do this, if you are merely embedding a react component in your Rails view, is to retrieve the csrf token from your rails view and then pass it as a header in your fetch api call.
You can get the csrf token by doing something like this:
const csrf = document.querySelector("meta[name='csrf-token']").getAttribute("content");
And then you just pass it as a header in your fetch call:
...
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrf
},
...
I normally don't use fetch, so not too sure about the exact syntax, but this should help guide you.
Thanks! I ended up with this as a working solution:
In the view that renders my react component
<% csrf_token = form_authenticity_token %>
<%= react_component('ExerciseDisplay', {
program: #program.subprograms.first.exercises, ids: {sub_id: #program.subprograms.first.id, team_id: #team.id, token: csrf_token}
}) %>
I passed the token into state, then accessed it via fetch:
fetch(POST_PATH, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': this.state.ids.token
},
body: body
}).then(res => res.json()).then(console.log);
Inside your form element, add a authenticity_token:
<input type="hidden" name="authenticity_token" value={csrf}/>
Set the value as per the below:
const csrf = document.querySelector("meta[name='csrf-token']").getAttribute("content");
I too faced the same issue when using rails 5.2 and i was able to fix this issue by adding
protect_from_forgery with: :null_session in application_controller.rb i got this from here,please refer this

#<RestClient::NotFound: 404 Not Found> error + rest-client gem

I'm getting the below error for rest-client gem while file uploading. Gem is installed properly.
require 'rest-client'
class SimpleService
include RestClient
// other methods //
def update_request method, opts ={}
headers = set_request_header
payload = opts
url = #base_uri + url_path(method)
begin
# RestClient.put url, payload, headers
RestClient::Request.execute(method: :put, url: url,
payload: payload, headers: headers)
rescue RestClient::ExceptionWithResponse => e
byebug
e.response
end
end
end
parameters for the rest client is
headers is {"Authorization"=>"ApiKey SHctT2tSNE94Ijp0cnVlfQ.4ylSKUJurtqCqfiNcm2vRROyHyWjJxWi0WFLsABLY74", "content_type"=>"json"}
url is "https://sandbox.test-simplexcc.com/v2/users/604776/kyc"
payload is <ActionController::Parameters {"identity_kyc_docunt_1"=>#<ActionDispatch::Http::UploadedFile:0x007fe2183a6d10 #tempfile=#<Tempfile:/var/folders/95/z56d5kd10_sb7s82b982fpjw0000gn/T/RackMultipart20180628-1288-1oncnou.png>, #original_filename="35155-6-adventure-time-picture.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"identity_kyc_docunt_1\"; filename=\"35155-6-adventure-time-picture.png\"\r\nContent-Type: image/png\r\n">, "controller"=>"simplex", "action"=>"update_kyc"} permitted: true>
I'm using the postman client call my rest end points. for every request im getting the same error.
(byebug) e
#<RestClient::NotFound: 404 Not Found>
I tried other rest client gem calls to invoke the endpoints. for everything i'm getting the same error.
Thanks
Ajith
I had to convert the payload to json and it solved the problem.
RestClient::Request.execute(method: :put, url: url,
payload: payload.to_json, headers: headers)

how to access this kind of hash

I am using RestClient to make a post request and i made it so i an error response back so i can print those error messages in console
i tried the following per the restclient gem documentation
begin
response = RestClient.post base_uri, params.to_json, content_type: 'application/json', accept: 'application/json'
rescue RestClient::ExceptionWithResponse => err
error = err.response
p "this is the error response #{error}"
end
when i print err.response i get the following
"this is the error response {\"error\":{\"message\":\"An active access token must be used to query information about the current us
er.\",\"type\":\"OAuthException\",\"code\":2500,\"fbtrace_id\":\"HTzmJ0CcIfd\"}}"
how do i access the message in the above hash to display it in console?
tried
p "this is the error response #{error.message}"
and it gives me "Bad request" - have no idea where it gets that
If you're just looking to output it:
error = JSON.load(err.response)
puts error['error']['message']
You can always format it a bit better:
puts '[Code %d %s] %s' % [
error['error']['code'],
error['error']['type'],
error['error']['message']
]
Note that using puts inside of a Rails process is not going to work very well. You might want to use Rails.logger.debug instead.
The response you received is in JSON. You'll need to decode the JSON first and then interact with the data. Personally, I like MultiJson for this:
begin
response = RestClient.post base_uri, params.to_json, content_type: 'application/json', accept: 'application/json'
rescue RestClient::ExceptionWithResponse => err
error = MultiJson.load(err.response)
p "this is the error response #{error[:message]}"
end

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

Rails email using Postmark API on Heroku -- connection reset by peer

I have multiple bruises today, trying to learn two things at once... the API for Postmark and Rails HTTP requests.
Goal: Use Postmark add-on for Heroku to send production email.
I am trying to combine this article on HTTP requests...
http://docs.ruby-lang.org/en/2.0.0/Net/HTTP.html
... with this API reference for Postmark...
http://developer.postmarkapp.com/developer-send-api.html
Unfortunately, the examples from Postmark are done in curl and I have not succeeded in translating them into a HTTP request. I suspect the problem centers around the headers -- the parts of the transmission other than the body.
The rescue clause seen in the code below traps the error 'connection reset by peer'. At this point I don't know if I am even close to the right format for the headers that provide Postmark authentication.
I have the proper server token (in the config entry) and the From email has been given the required Postmark signature.
def send_production_email(email_address, subject, email_body)
# Use API to interact with Heroku add-on Postmark
# http://developer.postmarkapp.com/developer-send-api.html
uri = URI('https://api.postmarkapp.com/email')
# Form the request
req = Net::HTTP::Post.new(uri)
# Set request headers -- SUSPECT THIS IS WRONG
req['Accept'] = 'application/json'
req['Content-Type'] = 'application/json'
req['X-Postmark-Server-Token'] = Rails.application.config.postmark_token
rbody ={
'From' => 'Support <michael#mydomain.com>',
'To' => email_address,
'Subject' => subject,
'HtmlBody' => wrap_html(email_body),
'TextBody' => email_body
}.to_json
req.body = rbody
# Send the request, waiting for the response
begin
response = Net::HTTP.new(uri.host, uri.port).start {|http| http.request(req) }
rescue Exception => e
logthis("http request error: #{e.message}")
return
end
# ...parsing section omitted since I do not get that far...
end
A second attempt was formatted this way, but results in the same peer reset error:
rbody ={
'From' => 'Support <michael#disambiguator.com>', # TODO: replace email when domain is live
'To' => email_address,
'Subject' => subject,
'HtmlBody' => wrap_html(email_body),
'TextBody' => email_body
}.to_json
uri = URI('https://api.postmarkapp.com/email')
http = Net::HTTP.new(uri.host, uri.port)
# http.use_ssl = true
request = Net::HTTP::Post.new(uri.path, {'Content-Type' => 'application/json', 'Accept' => 'application/json', 'X-Postmark-Server-Token' => Rails.application.config.postmark_token})
request.body = rbody
# Send the request, waiting for the response
begin
response = http.request(request)
rescue Exception => e
logthis("http request error: #{e.message}")
return
end
I am grateful for any guidance!
I’m a Wildbit’s employee and the maintainer of the official Postmark Ruby gem.
The "connection reset by peer" error is the result of you trying to send an unencrypted HTTP request to an endpoint expecting secure communication via HTTPS. So, if you change this line:
Net::HTTP.new(uri.host, uri.port).start {|http| http.request(req) }
to:
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
response = http.start { |http| http.request(req) }
then you should be able to receive a response from the API. I see that you have this line in the second example, but it is commented. Since you’re doing this as an exercise, I’d like to add that when using net/http you don’t usually have to work with the underlying classes like Net::HTTP::Post. It’s generally simpler to use the higher level API provided by instances of the Net::HTTP class. Here is an example of how your method could be simplified by using it:
def send_production_email(email_address, subject, email_body)
uri = URI('https://api.postmarkapp.com/email')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
headers = {'Accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Postmark-Server-Token' => Rails.application.config.postmark_token}
payload = {'From' => 'tema#wildbit.com',
'To' => email_address,
'Subject' => subject,
'HtmlBody' => email_body,
'TextBody' => email_body}
http.post(uri.request_uri, payload.to_json, headers)
rescue => e
puts "http request error: #{e.message}"
end
And, if you’re interested in how net/http is used in the official Postmark Ruby gem, check out the HttpClient class’ source.

Resources