solidservice icon indicating copy to clipboard operation
solidservice copied to clipboard

Call parameters validation

Open vibze opened this issue 3 years ago • 3 comments

Firstly, thank you for making this great library. I really like the simplicity of it and how it also simplifies the service pattern with bubbling exceptions.

I have run into some head scratching today when I got private method fail called for nil:Class today.

After looking at code it appeared that service initialization in call method was failing because I have passed ActionController::Parameters instance in place of parameters. So initializer failed and there was no instance of service in rescue block.

Maybe it could be feasible to validate parameters or make some kind of universal conversion for them so it won't break on initialization.

vibze avatar Jun 09 '22 09:06 vibze

Thanks for trying this gem. Could you put some code examples here for me to test?

hoppergee avatar Jun 09 '22 14:06 hoppergee

Simplified example would be

require 'solidservice'

class UserService < SolidService::Base
  def call
    success(params[:number] + 1)
  end
end

UserService.call(1)

Which throws /var/lib/gems/2.7.0/gems/solidservice-1.0.0/lib/solidservice/base.rb:18:in rescue in call': private method fail' called for nil:NilClass (NoMethodError).

In this example it's clear that I'm passing something which I shouldn't pass. What got me confused is that doing something like this in the controller:

UserService.call(params.require(:user))

would throw the same exception and it was pretty hard to find the reason without reading the code of the gem. So a type check with descriptive error message would be nice.

I think that the exception itself happens because .with_indifferent_access is a hash method, which doesnt exist on ActionController::Parameters that is used to hold request parameters in controllers.

In order for this to work I had to do

UserService.call(params.require(:user).to_h)

which I find not too elegant

vibze avatar Jun 09 '22 19:06 vibze

I never use it this way. I would do it like this:

UserService.call(
  user_params: params.require(:user)
)

But yes, you're right. I should have provided a more reasonable error message for this circumstance. Thanks!

hoppergee avatar Jun 10 '22 03:06 hoppergee