ruby-on-rails - pruebas - rails web service json
Es necesario devolver el error 404 con formato JSON en Rails (4)
Tengo una interfaz HTML normal y una API JSON en mi aplicación Rails. Ahora, si alguien llama a /api/not_existent_method.json
, devuelve la página HTML 404 predeterminada. ¿Hay alguna manera de cambiar esto a algo así como {"error": "not_found"}
mientras se deja la página 404 original para la interfaz HTML intacta?
Claro, se verá algo como esto:
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
no es el nombre real de la excepción. Variará con la versión de Rails y el comportamiento exacto que desee. Bastante fácil de encontrar con una búsqueda en Google.
Intenta poner al final de tus routes.rb
:
match ''*foo'', :format => true, :constraints => {:format => :json}, :to => lambda {|env| [404, {}, [''{"error": "not_found"}'']] }
Me gusta crear un controlador API independiente que establezca el formato (json) y los métodos específicos de la 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
Prueba de RSpec:
it ''should return 404'' do
get "/api/route/specific/to/your/app/", format: :json
expect(response.status).to eq(404)
end
Un amigo me señaló una solución elegante que no solo maneja 404 sino también 500 errores. De hecho, maneja todos los errores. La clave es que cada error genera una excepción que se propaga hacia arriba a través de la pila de middlewares de rack hasta que es manejado por uno de ellos. Si está interesado en aprender más, puede ver este excelente screencast . Rails tiene sus propios manejadores para las excepciones, pero puede anularlos mediante la opción de configuración exceptions_app
menos documentada. Ahora puede escribir su propio middleware o puede enrutar el error en rieles, como este:
# In your config/application.rb
config.exceptions_app = self.routes
Entonces solo tienes que hacer coincidir estas rutas en tu config/routes.rb
:
get "/404" => "errors#not_found"
get "/500" => "errors#exception"
Y luego solo creas un controlador para manejar esto.
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
Una última cosa para agregar: en el entorno de desarrollo, los rieles usualmente no representan las páginas 404 o 500, sino que imprimen una traza inversa. Si desea ver su ErrorsController
en acción en el modo de desarrollo, deshabilite la ruta de retroceso en su archivo config/enviroments/development.rb
.
config.consider_all_requests_local = false