Подтвердить что ты не робот

Как обрабатывать исключения в коде RESTful на основе JSON?

У меня есть приложение "программное обеспечение как услуга", которое использует JSON, переданный через API RESTful.

Проще говоря: каковы наилучшие методы для сбора и отчетности исключений при использовании RESTful API с обменом данными JSON?

Моя первая мысль заключалась в том, чтобы увидеть, что делает 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 отправляет несуществующий идентификатор, например

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?

Итак, в общем, я punt и позволяю ActionController генерировать HTML, если есть ошибка? Это не кажется правильным...

4b9b3361

Ответ 1

(Я нашел ответ перед тем, как я ударил [Отправить свой вопрос]. Но это может помочь и другому...)

Ответ заключается в использовании 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

Ответ 2

Если это помогает кому-то, это то, что я сделал, как поймать все для моей чисто json api:

В вашем ApplicationController, который наследуется каждым конкретным контроллером, добавьте

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

# ...

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

# ...
  • основывается главным образом на бесстрашном ответе

Ответ 3

Как разработчик, вы также захотите увидеть следы (желательно с полезными линиями, отфильтровывая драгоценные камни). И сделать следы невидимыми для производства:

  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

Ответ 4

Нет четкого консенсуса относительно того, как сохранить согласованный стандарт для написания кода JSON API, но это часть того, что я тренирую (больше, чем вы просили):

  • Держите это просто - постарайтесь оставаться спокойным. Пользовательские методы могут сделать вещи сложными быстро.
  • Попросите сервер вернуть собственные коды ошибок и используйте "rescue_from" для захвата и
  • в других случаях отображать Rails-коды ответа HTTP, которые могут быть специально нацелены на клиентское приложение.

В вашем случае вы можете найти Rails reply_to и reply_with обрабатывать html/json/другие ответы с грацией. И даже в вашем решении он по-прежнему будет эффективно отображать HTML, но это не то, что будет интерпретировано вашим клиентским приложением, которое вместо этого будет читать HTTP-заголовок и получить код ответа HTTP, что и запускает ваш "rescue_from",.