HTTP status code when sending email failed - ruby-on-rails

Note: I have read this but I still don't know how to go about building the sending email function correctly, so I ask this question. I need to know the HTTP status code to use when email sending succeed/failed, or if that's not the right thing to do, the right thing to do.
A POST request to my rails app will send an email.
If the email sending failed, what HTTP status code should I return to the person who send the POST request in my JSON response?
def inform
delivered = true
begin
UserMailer.new_comment(current_user, other_user, #note).deliver_now
rescue Net::SMTPAuthenticationError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Net::SMTPFatalError, Net::SMTPUnknownError
delivered = false
end
if delivered
# I use :created here because email is created
render json: { delivered: true }.to_json, status: :created
else
# I use :service_unavailable here because email sending failed
render json: { delivered: false }.to_json, status: :service_unavailable
end
end

502
bad_gateway
Typically used for upstream server failure.
Here's some more info: https://airbrake.io/blog/http-errors/502-bad-gateway-error
a 502 Bad Gateway Error means that a server that is upstream to one that you (the client) are connecting to has run into trouble. In this scenario, this means that the server providing the 502 Bad Gateway Error is acting as a gateway

I would rather use code 424 https://www.rfc-editor.org/rfc/rfc4918#section-11.4
The 424 (Failed Dependency) status code means that the method could
not be performed on the resource because the requested action
depended on another action and that action failed. For example, if a
command in a PROPPATCH method fails, then, at minimum, the rest of
the commands will also fail with 424 (Failed Dependency).

Related

How to disable SSL in a single Rack::Proxy request within an SSL enabled Rails application?

I have an SSL enabled application and I'm redirecting a specific request to an older application, in order to avoid CORS issues. In fact this is a .Net application that will process print requests but it does not support SSL. The redirected request tries to connect with SSL resulting with the following in the Rails app logs...
OpenSSL::SSL::SSLError (SSL_connect returned=1 errno=0 state=SSLv3/TLS write client hello: wrong version number):
The other application simply doesn't support SSL so its nothing to do with verifying SSL certificates or SSL version numbers.
Currently I'm using the following function, which works a treat when the app is not running in under SSL
def perform_request(env)
request = Rack::Request.new(env)
if request.path.include? "proxy_process_dispatch"
env["http.read_timeout"] = (OFFICE_PRINT_TIMEOUT / 1000) - 1
env["HTTP_HOST"] = OFFICE_IP + ':' + OFFICE_PRINT_SERVER_PORT
env["REQUEST_PATH"] = "/?process=true"
super(env)
else
#app.call(env)
end
end
It seems that because the original request was SSL the redirected request is also SSL but I need to ensure that its a standard HTTP request, though on a non-standard port.
OK, so I decided that I was going about this the wrong way and rather than using Rack::Proxy to divert requests to avoid CORS issues I simply used the Net:HTTP functions to make a new, simple, request. So my application makes a JS request to my rails application and my rails routes directs the request to a controller function as follows: -
require "net/http"
require "uri"
def process_dispatch_list
uri = URI.parse("http://#{OFFICE_IP}")
http = Net::HTTP.new(OFFICE_IP, OFFICE_PRINT_SERVER_PORT)
http.use_ssl = false
http.read_timeout = (OFFICE_PRINT_TIMEOUT / 1000) - 1
request = Net::HTTP::Get.new(uri.request_uri + "?process_dispatch=true")
response = http.request(request)
case response
when Net::HTTPSuccess
render json: response.body, status: :ok
else
render json: response.body, status: :unprocessable_entity
end
end
Works a treat, my response is interpreted in the front end ajax request and reports success of failure using pnotify based on the response status. No need Rack:Proxy anymore either.

Response must exactly match validationToken query parameter

I am using Microsoft Graph and had successfully set up the ability to create subscriptions and receive push notifications. However, the process of creating a subscription is no longer working and I am stumped.
2018-01-25T23:32:41.694741+00:00 app[web.1]:
OData::ClientError (400 InvalidRequest:
"Subscription validation request failed.
Response must exactly match validationToken query parameter."
from "https://graph.microsoft.com/beta/subscriptions"):
Code to return validationToken in response. When I curl, my response is exactly as it should be.
def outlook_subscription
render plain: params[:validationToken]
head 200
end
Nothing has changed on our end. Since when did you start seeing this problem ? Did you deploy any new version of your (or the backed library) code ?
Please check the request/response in your logs and check if they both match (case sensitive).
This work for me!
def outlook_subscription
render json: params[:validationToken], content_type: "plain/text", status: 200
end

Rails API: How do you standardize your JSON responses?

Right now, upon a successful call to my Rails API Backend, I might do one of the following...
render json: {user_id: #user.id, token: token}
or
render json: {status: :success}
And upon an unsuccessful result, I may do something like
render json: {status: :failure, error: "The email or password entered is not correct."}
My question is... what's the best way to standardize this.
If my iOS app goes searching for a json dictionary value of dict[#"error"] it's not always going to find it. Should every single render message I have regardless of success... have a 'status' key, or an 'error' key or both.
Or is it better for the front end to deal with this, and if dict[#"error"]/dict[#"status"] happen to not exist... then it knows the back end did not have an error occur otherwise it would have said so?
The way you are rendering the responses is fine. On your client side, it's should be all about handling properly HTTP status codes.
render status: :ok -> should return a HTTP status code 200, which means a successful request. Then your client (iphone app) does know that with a successfull request you get the user id and token.
render status: :bad_request -> should return a HTTP status code 400, which means unsuccessfull request, then your client would know that an error occured, and based on your standards he can look up the error field of the json response
I had the similar question in terms of how do we standardize the JSON response.
By default Rails generates this sort of JSON from a post model,
posts: [
{
id: 22198,
title: "Using GitHub Pages To Host Your Website",
date: "2013-08-16 09:30:20",
},
{
id: 22196,
title: "Running Tests in Ruby on Rails – Treehouse Quick Tip",
date: "2013-08-15 14:30:48",
}
]
But is there any standard to power the Rails API for an iPhone APP?
What are the standards or typical success/failure response format an iOS developer would expect to see?

how do you write json response destroy methods correctly in rails?

Here's the code for sending a json response associated with a working and non working status. Does anyone have recommendations for other resources? This isn't working. Thank you.
if #content.destroy
format.json { redirect_to #collection, status: :destroyed, notice 'Content was removed from collection.' }, :status => 200
else
format.json { render json #content.errors, status: :unprocessable_entity }, :status => 400
end
TL;DR: if you are using some JS framework, then look up how that framework wants success and failure response to look like, if you are rolling your own - then do whatever makes more sense for you.
Long version:
There are couple ways you can return response from rails to your web app. Rails by default returns status code 2xx for success and 4xx for failed requests. Some web frameworks such as Extjs, like to receive response with 200 code always and look at success key in the response to see if the request was successfult. If you are writing your own JS that utilizes XHR, then you can do whatever you want: its up to you how you architect your API. I find it useful to return json response from server with 200 code and set success key to true or false so in my callback JS i can write something like:
if(request.data.success){
successfulPost(response);
} else {
failed(response);
}
one of the reasons I prefer that approach is that, if there is an exception, then I can actually distinguish from record not being saved due to validation errors as opposed to bug in code that caused exception. But that is a personal preference and some may argue that error is error and it does not matter what caused it.

Client Side Validation, disabled_validators = [:uniqueness], returns 500 http status

In my rails4 project I am using the client side validation gem (branch 4-0-beta).
For security reasons I have disabled the uniqueness validation in the config/initializers/client_side_validations.rb file.
ClientSideValidations::Config.disabled_validators = [:uniqueness]
This works fine and when I test in the browser whether a user email exists I get a 500 status no matter if the user exists or not.
http://localhost:3000/validators/uniqueness?case_sensitive=false&id=01&user[email]=tester#mail.com&_=1379052030490
(If uniqueness is not disabled I get a 200 or 404 status response dependent on whether the user is unique or not.)
HTTP Status Code
However I am not sure if I understand correctly the status code defined in middleware.rb:
client_side_validations / lib / client_side_validations / middleware.rb
def call(env)
if matches = /^\/validators\/(\w+)$/.match(env['PATH_INFO'])
if ClientSideValidations::Config.disabled_validators.include?(matches[1].to_sym)
[500, {'Content-Type' => 'application/json', 'Content-Length' => '0'}, ['']]
else
"::ClientSideValidations::Middleware::#{matches[1].camelize}".constantize.new(env).response
end
else
#app.call(env)
end
end
end
My understanding is that status code 500 should be used for server errors ("A generic error message, given when no more specific message is suitable"). However in this case the uniqueness validation is disabled on purpose and I was therefore thinking whether a 403 "Forbidden" or 405 "Method not allowed" would be more appropriate?
The reason why I am not too happy about the 500 status is that Chrome will automatically display a server error message, and since the client_side_validation gem is not raising an exception, which I can catch within rails, I am stuck with Chrome's default server error message for 500 status code.
Any advice on the appropriate status code in this situation or alternative solutions would be cool.

Resources