J'ai un front-end HTML normal et une API JSON dans mon application Rails. Maintenant, si quelqu'un appelle /api/not_existent_method.json
il renvoie la page HTML 404 par défaut. Y a-t-il un moyen de changer cela en quelque chose comme {"error": "not_found"}
tout en laissant intacte la page 404 originale pour le frontend HTML ?
Réponses
Trop de publicités?Un ami m'a orienté vers une solution élégante qui gère non seulement les erreurs 404 mais aussi 500. En fait, elle traite toutes les erreurs. La clé est que chaque erreur génère une exception qui se propage vers le haut de la pile de middlewares de rack jusqu'à ce qu'elle soit traitée par l'un d'entre eux. Si vous souhaitez en savoir plus, vous pouvez regarder cet excellent screencast . Rails possède ses propres gestionnaires d'exceptions, mais vous pouvez les remplacer par l'outil moins documenté exceptions_app
option de configuration. Maintenant, vous pouvez écrire votre propre intergiciel ou vous pouvez renvoyer l'erreur dans rails, comme ceci :
# In your config/application.rb
config.exceptions_app = self.routes
Ensuite, il suffit de faire correspondre ces routes dans votre config/routes.rb
:
match "/404" => "errors#not_found"
match "/500" => "errors#exception"
Et ensuite vous créez un contrôleur pour gérer ça.
class ErrorsController < ActionController::Base
def not_found
if env["REQUEST_PATH"] =~ /^\/api/
render :json => {:error => "not-found"}.to_json, :status => 404
else
render :text => "404 Not found", :status => 404 # You can render your own template here
end
end
def exception
if env["REQUEST_PATH"] =~ /^\/api/
render :json => {:error => "internal-server-error"}.to_json, :status => 500
else
render :text => "500 Internal Server Error", :status => 500 # You can render your own template here
end
end
end
Une dernière chose à ajouter : dans l'environnement de développement, rails ne rend généralement pas les pages 404 ou 500 mais imprime un backtrace à la place. Si vous voulez voir votre ErrorsController
en action dans le mode de développement, puis désactivez le backtrace dans vos config/enviroments/development.rb
fichier.
config.consider_all_requests_local = false
J'aime créer un contrôleur d'API distinct qui définit le format (json) et les méthodes spécifiques à l'API :
class ApiController < ApplicationController
respond_to :json
rescue_from ActiveRecord::RecordNotFound, with: not_found
# Use Mongoid::Errors::DocumentNotFound with mongoid
def not_found
respond_with '{"error": "not_found"}', status: :not_found
end
end
Test RSpec :
it 'should return 404' do
get "/api/route/specific/to/your/app/", format: :json
expect(response.status).to eq(404)
end
Bien sûr, ça ressemblera à quelque chose comme ça :
class ApplicationController < ActionController::Base
rescue_from NotFoundException, :with => :not_found
...
def not_found
respond_to do |format|
format.html { render :file => File.join(Rails.root, 'public', '404.html') }
format.json { render :text => '{"error": "not_found"}' }
end
end
end
NotFoundException
est pas le nom réel de l'exception. Il varie en fonction de la version de Rails et du comportement exact que vous souhaitez. Il est assez facile à trouver avec une recherche Google.