Handling & returning validation errors in an JSON API application

@jodosha Another question came up regarding uniqueness validations. I’m handling them on the database level with an unique index. When this rule is violated an Sequel::UniqueConstraintViolation error is raised.

How would you handle this in an action? (Taking into consideration that the client should get an response with the errors.)

As far as I can tell handle_exception doesn’t work in this case since it only takes an HTTP status code. Then I tried to add the error to the errors but could not find an appropriate public API within lotus/validation. My current solution looks like the following, I’m hoping it can be DRY’ed up a little bit.

module Datsu::Controllers::Identities
  class Create
    include Datsu::Action

    expose :identity

    params do
      param :identity do
        param :email, presence: true
        param :password, presence: true
      end
    end

    def initialize(repository = IdentityRepository)
      @repository = repository
    end

    def call(params)
      @identity = Identity.new params[:identity]
      @repository.create @identity
    rescue Sequel::UniqueConstraintViolation
      halt_with_error 'identity.email', :uniqueness
    end
  end
end
module ParameterValidation
  private
  def validate!
    halt_with_errors(error_map) unless params.valid?
  end

  def error_map
    errors.to_h.inject({}) { |hash, (key, value)| hash.merge({ key.to_sym => value.map(&:validation) }) }.to_h
  end

  def halt_with_errors(errors)
    halt 422, JSON.generate({ errors: errors })
  end

  def halt_with_error(attribute, error)
    halt_with_errors({ attribute => [ error ] })
  end
end