pragmarb/pragma

Decorate errors automatically

aldesantis opened this issue · 1 comments

Related to pragmarb/pragma-operation#2.

This pattern is very annoying:

options['result.response'] = Pragma::Operation::Response::NotFound
  .new
  .decorate_with(Pragma::Decorator::Error)

There is no reason for that decorate_with to exist, it's just boilerplate.

If result.response is a Pragma error response and it's not decorated, we should decorate it with Pragma::Decorator::Error automatically.

We either do it in pragma-operation or decorate the base operation here, e.g.

class Pragma::Operation::Base < Trailblazer::Operation
  def call(*)
    result = super
    result['result.response'] = '...'
  end
end

The problem with this is it cannot be overridden since it's not a step, and there is no way to ensure a step is actually run at the end of the operation.

I wonder whether this could be implemented in the form of response transformers, e.g.

class Pragma::Transformer::CastSymbol < Pragma::Transformer::Base
  def call(options)
    return unless options['result.response'].is_a?(Symbol)
    response_klass = "Pragma::Operation::Response::#{options['result.response'].to_s.camelize}"
    options['result.response'] = response_klass.constantize
  end
end

class Pragma::Transformer::Instantiate < Pragma::Transformer::Base
  def call(options)
    return unless options['result.response'] < Pragma::Operation::Response::Base
    options['result.response'] = options['result.response'].new
  end
end

class Pragma::Transformer::DecorateErrors < Pragma::Transformer::Base
  def call(options)
    return unless options['result.response'].entity.is_a?(Pragma::Error)
    options['result.response'].decorate_with(Pragma::Decorator::Error)
  end
end

Pragma::Operation::Base.transformers << Pragma::Transformer::CastSymbol
Pragma::Operation::Base.transformers << Pragma::Transformer::Instantiate
Pragma::Operation::Base.transformers << Pragma::Transformer::DecorateErrors

Then we could do

options['result.response'] = :not_found

and get the response instantiated and decorated.

I imagine this would be its own gem. In any case, it only makes sense if it would also be used in other places.

My other concern is that this could very easily be abused to add steps to an operation without having to call step. Perhaps we should only allow to manipulate the response and nothing else?