J'ai une application "logicielle en tant que service" qui utilise Json communiquée via une API reposante.
Simplement indiqué: Quelles sont les meilleures pratiques pour la capture et la signalisation des exceptions lors de l'utilisation d'une API reposante avec l'échange de données JSON?
Ma première pensée était de voir ce que Rails le fait en générant un échafaud, mais ce n'est clairement pas raison. Voici un extrait:
class MumblesController < ApplicationController
# GET /mumbles/1
# GET /mumbles/1.json
def show
@mumble = Mumble.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @mumble }
end
end
end
Dans ce cas, si le code JSON envoie un identifiant inexistant, par exemple.
http://www.myhost.com/mumbles/99999.json
puis mumble.find () va élevera Activerecord :: recordNotfound. ActionController attrapera cela et rendre une page d'erreur dans HTML. Mais HTML est inutile au client qui attend JSON.
Je pourrais contourner cela en enveloppant le Mumble.Find () dans un begin ... rescue RuntimeError
bloquer et rendu un statut JSON =>: non productible ou quelque chose.
Mais alors si l'application du client envoie un chemin non valide, E.G.:
http://www.myhost.com/badtypo/1.json
Une application basée sur JSON est-elle censée capter cela et retourner une erreur dans Json? Si oui, où puis-je capturer cela sans creuser profondément dans ActionDispatch?
Alors, Globalement, est-ce que je punt et que l'actionController générer HTML s'il y a une erreur? Ça ne se sent pas juste ...
(J'ai trouvé la réponse juste avant que je frappe [post votre question]. Mais cela pourrait aider quelqu'un d'autre aussi bien ...)
rescue_from
La réponse est d'utiliser l'actionController rescue_from
, comme décrit dans ce guide et documenté ici . En particulier, vous pouvez remplacer le rendu par défaut des fichiers par défaut 404.html et 500.html dans ces lignes:
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found
private
def record_not_found(error)
render :json => {:error => error.message}, :status => :not_found
end
end
Si cela aide quiconque, c'est ce que j'ai fait comme une capture pour mon API purement JSON:
Dans votre ApplicationController
que chaque contrôleur spécifique hérite de, ajouter
# app/controllers/api/v1/application_controller.rb
# ...
rescue_from StandardError do |exception|
render json: { :error => exception.message }, :status => 500
end
# ...
En tant que développeur, vous voudrez également voir des traces (de préférence avec des lignes utiles, filtrer des gemmes). Et faire des traces invisibles pour la production:
rescue_from StandardError do |exception|
# Handle only JSON requests
raise unless request.format.json?
err = {error: exception.message}
err[:backtrace] = exception.backtrace.select do |line|
# filter out non-significant lines:
%w(/gems/ /rubygems/ /lib/Ruby/).all? do |litter|
not line.include?(litter)
end
end if Rails.env.development? and exception.is_a? Exception
# duplicate exception output to console:
STDERR.puts ['ERROR:', err[:error], '']
.concat(err[:backtrace] || []).join "\n"
render :json => err, :status => 500
end
Il n'y a pas de consensus clair sur la manière de conserver une norme cohérente pour la rédaction du code API JSON, mais c'est une partie de ce que je pratique (plus que ce que vous avez demandé):
Dans votre cas, vous pourriez trouver le Rails répond_to et réponse_with gérer HTML/JSON/Autres réponses avec Grace. Et même dans votre solution, cela rendra effectivement rendu le HTML, mais ce n'est pas ce que Sera interprété par votre application client, qui va plutôt lire l'en-tête HTTP et obtenir le code de réponse HTTP, ce qui est ce qui déclenche votre "sauvetage_from".