web-dev-qa-db-ja.com

JSONベースのRESTfulコードで例外を処理する方法

RESTful APIを介して通信されるJSONを使用する「サービスとしてのソフトウェア」アプリがあります。

簡単に言うと、JSONデータ交換でRESTful APIを使用する場合の例外のキャプチャとレポートのベストプラクティスは何ですか?

私の最初の考えは、Railsが足場を生成することによって何を行うかを確認することでしたが、それは明らかに正しくありません。ここに抜粋があります:

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

この場合、JSONコードが存在しないIDを送信するとします。

http://www.myhost.com/mumbles/99999.json

次に、Mumble.find()はActiveRecord :: RecordNotFoundを発生させます。 ActionControllerはそれをキャッチし、エラーページをHTMLでレンダリングします。しかし、HTMLはJSONを期待しているクライアントには役に立たない。

Mumble.find()をbegin ... rescue RuntimeErrorブロックでラップし、JSONステータス=>:unprocessable_entityなどをレンダリングすることで、これを回避できます。

しかし、クライアントのアプリが無効なパスを送信した場合はどうなりますか。例:

http://www.myhost.com/badtypo/1.json

JSONベースのアプリはそれをキャッチしてJSONでエラーを返すことになっていますか?その場合、ActionDispatchを深く掘り下げることなく、どこでそれをキャプチャできますか?

全体として、エラーが発生した場合、パントしてActionControllerにHTMLを生成させますか?それは正しくないと思います...

37
fearless_fool

([質問を投稿]を押す直前に答えが見つかりました。しかし、これは他の人にも役立つかもしれません...)

ActionControllerのrescue_fromを使用します

答えは、ActionControllerのrescue_fromを使用することです。説明は このガイドで と記載されています ここ 。特に、デフォルトの404.htmlおよび500.htmlファイルのデフォルトのレンダリングを次のように置き換えることができます。

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
77
fearless_fool

それが誰かを助けるなら、これは私が純粋にjson apiのすべてをキャッチするために私がしたことです:

特定の各コントローラーが継承するApplicationControllerに、以下を追加します

# app/controllers/api/v1/application_controller.rb

# ...

rescue_from StandardError do |exception|
    render json: { :error => exception.message }, :status => 500
end

# ...
  • 大部分はfearless_foolの答えに基づいています
7
Tim S

開発者は、トレースも確認する必要があります(できれば、有用な行を使用して、gemを除外します)。そして、生産のためにトレースを見えなくします:

  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
3

JSON APIコードを作成するための一貫した標準を維持する方法について明確なコンセンサスはありませんが、これは私が実践していることの一部です(あなたが要求したものよりも):

  1. シンプルに保つ-落ち着いて滞在するようにしてください。カスタムメソッドを使用すると、物事をすばやく複雑にすることができます。
  2. サーバーにネイティブエラーコードを返させ、「rescue_from」を使用してキャプチャします。
  3. それ以外の場合は、Rails HTTP応答コードをレンダリングします。これは、クライアントアプリが具体的にターゲットにすることができます。

あなたの場合、Rails respond_toとrespond_withがhtml/json /その他の応答を適切に処理します。ソリューションでも、HTMLを効果的にレンダリングしますが、これはクライアントアプリによって解釈され、代わりにHTTPヘッダーを読み取り、HTTP応答コードを取得します。これが「rescue_from」をトリガーしているものです。

1
Carson Cole