Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/adham90/command_service_object

:package: :octopus: command_service_object gem helps you to generate service and command objects using rails generator.
https://github.com/adham90/command_service_object

command domain-driven-design generator rails rails-generator service service-object

Last synced: 3 months ago
JSON representation

:package: :octopus: command_service_object gem helps you to generate service and command objects using rails generator.

Awesome Lists containing this project

README

        

# CommandServiceObject

Rails Generator for command service object.

## Theory

[Command Design Pattern](https://en.wikipedia.org/wiki/Command_pattern) consists of `Command Object` and `Service Object` (Executor), Command object is responsible for containing `Client` requests and run input validations on it to ensure that the request is valid and set default values, then `Service Object` applies the business logic on that command.

### Implementation

Service consists of several objects { `Command Object` `Usecase Object` And `Error Object` (business logic error) }.

- **[Command](https://en.wikipedia.org/wiki/Command_pattern):** the object that responsible for containing `Client` requests and run input validations it's implemented using [Virtus](https://github.com/solnic/virtus) gem and can use `activerecord` for validations and it's existed under `commands` dir.
- **Usecase:** this object responsible for executing the business logic, Every `usecase` should execute one command type only so that command name should be the same as usecase object name, usecase object existed under 'usecases` dir.
- **Micros:** Small reusable logic under the same service.
- **Externals:** Simple ruby module works as a service interface whenever you wanna call any external service or even service that lives under the same project you should use it.
- **Queries:** This dir is the only entry point for you to get any data form a service.
- **Listeners:** An event listener that waits for an event outside the service to occur.
- **Entities:** Many objects are not fundamentally defined by their attributes, but rather by a thread of continuity and identity.

### Result Object

In case of successful or failure `ApplicationService` the responsible object for all services will return `service_result` object this object contain `value!` method containing successful call result, and `errors` method containing failure `errors` objects.

### Helpers:

- Fail: You can use `fail!` helper to raise business logic failures, ex: `fail!('user should not have any active cards')`.
- Check: To do business logic validations you can use `check!` helper ex: `check!('user should not have any active cards') { user.active_cards.empty? }`, if the given block returns false then it will raise fail! with the given message.

> You can check if the result successful or not by using `ok?` method.

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'command_service_object'
```

And then execute:

`bundle`

Or install it yourself as:

`gem install command_service_object`

Next, you need to run the generator:

`rails generate service:install`

## Usage

$ rails g service [service_name] [usecases usecases]

### Generate Service ex

$ rails g service auth login
output

```bash
app/services/
├── application_service.rb
├── auth_service
│ ├ external/
│   ├── commands
│   │   └── login.rb
│   └── usecases
│   ├── login.rb
│   └── micros
├── case_base.rb
└── service_result.rb
```

### Generate micros ex

$ rails g service:micro auth generate_jwt_token_for

```bash
app/services/
├── auth_service
│   └── usecases
│   └── micros
│   └── generate_jwt_token_for.rb
```

```ruby
# app/services/auth_service/usecases/micros/generate_jwt_token_for.rb

module PaymentService::Usecases::Micros
class GenerateJwtTokenFor < CaseBase
def call
#
end
end
end
```

then you can edit command params
> you can read [Virtus gem docs](https://github.com/solnic/virtus) for more info.

```ruby
# app/services/auth_service/commands/login.rb
# frozen_string_literal: true

module AuthService::Commands
class Login < CommandBase
# You can read Virtus gem doc for more info.
# https://github.com/solnic/virtus

# Attributes
# attribute :REPLACE_ME, String

# Validations
# validates :REPLACE_ME, presence: true
end
end
```

and then add your business logic

```ruby
# app/services/auth_service/usecases/login.rb
# frozen_string_literal: true

module AuthService::Usecases
class Login < CaseBase
include CommandServiceObject::Hooks
micros :generate_jwt_token_for
#
# Your business logic goes here, keep [call] method clean by using private
# methods for Business logic.
#
def call
token = generate_jwt_token_for(cmd.user)
replace_me

output
end

def output
# return entity object
end

# This method will run if call method raise error
def rollback
# rollback logic
end

def allowed?
# policies loginc for issuer
# ex:
#
# return false if issuer.role != :admin

true
end

private

def replace_me
# [business logic]
end
end
end
```

### External APIs or Services

You can wrap external apis or services under `external/` dir

#### ex

```ruby
module External
module StripeService
extend self

def charge(customer:, amount:, currency:, description: nil)
Stripe::Charge.create(
customer: customer.id,
amount: (round_up(amount, currency) * 100).to_i,
description: description || customer.email,
currency: currency
)
end
end
end
```

usage from controller

```ruby
class AuthenticationController < ApplicationController
default_service :auth_service

def Login
cmd = command.new(params) # AuthService::Commands::Login.new
result = execute(cmd)

if result.ok?
render json: result.value!.as_json, status: 201
else
render json: { message: result.error }, status: 422
end
end
end
```

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/adham90/command_service_object. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).

## Code of Conduct

Everyone interacting in the CommandServiceObject project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/adham90/command_service_object/blob/master/CODE_OF_CONDUCT.md).