/operators-service

Service Object based on Either Monad

Primary LanguageRubyMIT LicenseMIT

Operators::Service

Gem Version CircleCI Maintainability

Operators::Service is a lightweight implementation of Service Object based on Either Monad. That gives an home of application business logic.

Service Objects are created when an action:

  • Uses integration with external services

  • Uses several models

  • Is complex (such as calculating sales statistics)

Installation

Add this line to your application's Gemfile:

gem 'operators-service'

And then execute:

$ bundle

Or install it yourself as:

$ gem install operators-service

Usage

class UserCreator < Operators::Service
  attr_reader :params
  
  def initialize(params)
    @params = params
  end

  def call
    user = User.create(params)
    if !user.new_record?
      success(user)
    else
      failure(user.errors)
    end
  end
end

success - returns instance of Dry::Monads::Either::Right

failure - returns instance of Dry::Monads::Either::Left

class UsersController < ApplicationController
  def create
    UserCreator.call(user_params).fmap do |user|
      render json: user
    end.or_fmap do |errors|
      render json: errors.full_messages
    end
  end
  
  private
  
  def user_params
    params.require(:user).permit!
  end
end

More complicated usage

If you need rescue_callbacks then you should define calling instead of call.

class Auth < Operators::Service
  rescue_callbacks AuthError, CredentialsError

  def initialize(options)
    @options = options
  end

  def calling
    return failure('User already authed') if @options[:failure] # returns Dry::Monads::Left('User already authed')

    first_auth_transaction
    second_auth_transaction

    success('ok') # returns Dry::Monads::Right('ok')
  end

  private

  def first_auth_transaction
    # do something...
  end

  def second_auth_transaction
    raise AuthError, 'Auth error message' if @options[:auth_error]
  end

  # Wrapper for your error result
  def error_wrap(error)
    error # 'User already authed' || 'Auth error message'
  end

  # Wrapper for your success results
  def success_wrap(success_result)
    success_result # ok
  end
end
success = Auth.call(email: 'email', password: 'password')
# Dry::Monads::Right('ok')

failure = Auth.call(email: 'email', password: 'password', failure: true)
# Dry::Monads::Left('User already authed')

raised_error = Auth.call(email: 'email', password: 'password', auth_error: true)
# Dry::Monads::Left('Auth error message')

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/operators-rb/operators-service.

License

The gem is available as open source under the terms of the MIT License.