0

J'ai passé une journée à essayer plusieurs approches, mais pas tout à fait arrivé là donc décidé de demander maintenant ...Comment gérer les erreurs génériques avec une réponse JSON dans une application hybride (JSON API + HTML) Rails 5?

J'ai une application Rails 5 qui est principalement une API JSON (en utilisant les spécifications JSON API réelles), mais aussi une application Rails "normale" avec des e-mails transactionnels et des pages liées au compte (réinitialiser le mot de passe, etc.). Ce que je voudrais réaliser est que Rails renvoie toujours une réponse JSON avec une réponse d'erreur significative à tous les appels API, plutôt que la page d'erreur HTML par défaut ou une erreur d'en-tête seulement 400.

Les principaux cas que j'essaie de gérer sont les problèmes d'analyse JSON et les exceptions Ruby (500 erreurs).

J'ai essayé:

  1. utilisant rescue_from au niveau ActionController - semble le cadre gère ces exceptions avant atteindraient le contrôleur
  2. leur manipulation au niveau du rack avec un middleware - cela a fonctionné dans le test mais pas dev malgré la mise en consider_all_requests_local-false dans les deux
  3. Enregistrement d'un nouveau type Mime et un analyseur comme JSON API Resources gem does it - semblait prometteur, mais le code de l'analyseur est jamais frappé

Je suis vraiment à ma fin de l'esprit, ce qui semblait si simple a fini par être trompeusement compliqué avec moi essayant de traquer où sont ces exceptions se traitées dans le cadre sans grand succès ...

Répondre

0

bien J'ai réussi à le résoudre à la fin, alors je pensais que je devais partager ce qui fonctionnait.

Ce que je manqué avant est que je devais jouer du violon un peu avec les types MIME pour que Rails comprendrait et bien utiliser l'API JSON:

config/initializers/mime_types.rb

JSON_API_MIME_TYPES = %w[ 
    application/vnd.api+json 
    text/x-json 
    application/json 
].freeze 

Mime::Type.unregister :json 
Mime::Type.register 'application/json', :json, JSON_API_MIME_TYPES 
Mime::Type.register_alias 'application/json', :json, %i[json_api jsonapi] 

Après cela, je pouvais enfin gérer 500 erreurs dans le contrôleur de base:

rescue_from StandardError, 
      with: :render_standard_error 

def render_standard_error 
    render json: { 
     status: 500, 
     error: 'Unhandled error', 
     message: 'An unexpected error occurred.' 
    }, status: :internal_server_error 
    end 

Ensuite, pour le traitement des erreurs d'analyse JSON, ce fut la solution:

app/middleware/catch_json_parse_errors

class CatchJsonParseErrors 
    def initialize(app) 
    @app = app 
    end 

    def call(env) 
    @app.call(env) 
    rescue ActionDispatch::Http::Parameters::ParseError => error 
    if JSON_API_MIME_TYPES.include?(env['CONTENT_TYPE']) || 
     JSON_API_MIME_TYPES.include?(env['HTTP_ACCEPT']) 
     return [ 
     400, { 'Content-Type' => 'application/json' }, 
     [{ 
      status: 400, 
      error: 'JSON parse error', 
      message: "There was a problem in the JSON you submitted: #{error}" 
     }.to_json] 
     ] 
    else 
     raise error 
    end 
    end 
end 

config/application.rb

require './app/middleware/catch_json_parse_errors' 
... 
config.middleware.use CatchJsonParseErrors