Skip to content

light-ruby/light-services

Repository files navigation

🚀 Light Services

Light Services is a simple yet powerful way to organize business logic in Ruby applications. Build services that are easy to test, maintain, and understand.

GitHub CI Codecov

Get started with Quickstart

Features

  • Simple: Define your service as a class with arguments, steps, and outputs
  • 📦 No runtime dependencies: Works stand-alone without requiring external gems at runtime
  • 🔄 Transactions: Automatically rollback database changes if any step fails
  • 🧬 Inheritance: Inherit from other services to reuse logic seamlessly
  • ⚠️ Error Handling: Collect errors from steps and handle them your way
  • 🔗 Context: Run multiple services sequentially within the same context
  • 🧪 RSpec Matchers: Built-in RSpec matchers for expressive service tests
  • 🌐 Framework Agnostic: Compatible with Rails, Hanami, or any Ruby framework
  • 🧩 Modularity: Isolate and test your services with ease
  • 100% Test Coverage: Thoroughly tested and reliable
  • ⚔️ Battle-Tested: In production use since 2017

Installation

gem "light-services", "~> 3.0"
rails generate light_services:install

Simple Example

class GreetService < Light::Services::Base
  # Arguments
  arg :name, type: String
  arg :age, type: Integer

  # Steps
  step :build_message
  step :send_message

  # Outputs
  output :message, type: String

  private

  def build_message
    self.message = "Hello, #{name}! You are #{age} years old."
  end

  def send_message
    # Send logic goes here
  end
end

Advanced Example (with dry-types and conditions)

class User::ResetPassword < Light::Services::Base
  # Arguments with dry-types for advanced validation and coercion
  arg :user, type: Types.Instance(User), optional: true
  arg :email, type: Types::Coercible::String, optional: true
  arg :send_email, type: Types::Params::Bool, default: true

  # Steps
  step :validate
  step :find_user, unless: :user?
  step :generate_reset_token
  step :save_reset_token
  step :send_reset_email, if: :send_email?

  # Outputs with dry-types
  output :user, type: Types.Instance(User)
  output :reset_token, type: Types::Strict::String

  private

  def validate
    errors.add(:base, "user or email is required") if !user? && !email?
  end

  def find_user
    self.user = User.find_by("LOWER(email) = ?", email.downcase)
    errors.add(:email, "not found") unless user
  end

  def generate_reset_token
    self.reset_token = SecureRandom.hex(32)
  end

  def save_reset_token
    user.update!(
      reset_password_token: reset_token,
      reset_password_sent_at: Time.current,
    )
  rescue ActiveRecord::RecordInvalid => e
    errors.from_record(e.record)
  end

  def send_reset_email
    Mailer::SendEmail
      .with(self) # Call sub-service with the same context
      .run(template: :reset_password, user:, reset_token:)
  end
end

Get started with Light Services

Rails Generators

Light Services includes Rails generators to help you quickly set up and create services in your Rails application.

Install Generator

Set up Light Services in your Rails application:

bin/rails generate light_services:install

This creates:

  • app/services/application_service.rb - Base service class for your application
  • config/initializers/light_services.rb - Configuration file
  • spec/services/application_service_spec.rb - RSpec test file (if RSpec is detected)

Options:

  • --skip-initializer - Skip creating the initializer file
  • --skip-spec - Skip creating the spec file

Service Generator

Create a new service class:

# Basic service
bin/rails generate light_services:service user/create

# Service with predefined structure
bin/rails generate light_services:service CreateOrder \
  --args=user product \
  --steps=validate process \
  --outputs=order

This creates:

  • app/services/user/create.rb - Service class file
  • spec/services/user/create_spec.rb - RSpec test file (if RSpec is detected)

Options:

  • --args - List of arguments for the service (e.g., --args=user product)
  • --steps - List of steps for the service (e.g., --steps=validate process)
  • --outputs - List of outputs for the service (e.g., --outputs=result)
  • --skip-spec - Skip creating the spec file
  • --parent - Parent class (default: ApplicationService)

Documentation

You can find the full documentation at light-services.kodkod.me.

License

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

About

Robust service architecture for Ruby frameworks

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Contributors 3

  •  
  •  
  •  

Languages