Simple Action provides a convenient DSL for building API endpoints and service objects. It builds significantly off the the parameter coercion/validation support provided by Simple Params simple_params.
The design of this gem was greatly influenced by this post by Philippe Creux: http://brewhouse.io/blog/2014/04/30/gourmet-service-objects.html
This class provides the following benefits for building API endpoints:
- Easy assignment and automatic validation of parameters with ActiveModel-like errors.
- A simple syntax for defining the execution block
- Easy validation, for integration into controllers
Add this line to your application's Gemfile:
gem 'simple_action'
And then execute:
$ bundle
Or install it yourself as:
$ gem install simple_action
A service class is defined by two things - the parameters it accepts, and the execute
method:
class RegisterUser < SimpleAction::Service
params do
param :name
param :age, type: :integer, validations: { numericality: { greater_than_or_equal_to: 18 } }
param :hair_color, default: "brown", validations: { inclusion: { in: ["brown", "red", "blonde", "white"] }}
end
def execute
user = User.create(name: name, age: age, hair_color: hair_color)
UserMailer.welcome_letter(user).deliver
user
end
end
The class is executed via a run
call to the class itself:
response = RegisterUser.run(name: "Tom", age: 21)
response.valid? #=> true
response.errors.empty? #=> true
response.result #=> User, id: 1, name: "Tom", age: 21
response = RegisterUser.run(name: nil, age: 21)
response.valid? #=> false
response.errors[:name] #=> ["can't be blank"]
response.result #=> nil
Building off of the example service class above, our controller logic can now be greatly simplified, as such
class UserController < ApplicationController
...
def new
@registration = RegisterUser.new
render action: :new
end
def create
registration = RegisterUser.run(params[:register_user])
if registration.valid?
@user = registration.result
redirect_to @user, notice: "Success!"
else
@registration = registration
render action: :new, alert: "Errors!"
end
end
Because the service class behaves like an ActiveModel object with regards to it's attribute assignment and parameter validation, it will continue to work with Rails forms.
By default, SimpleAction via SimpleParams will throw an error if you try to assign a parameter not defined within your class. However, you can override this setting to allow for flexible parameter assignment.
class FlexibleParams < SimpleAction::Service
params do
allow_undefined_params
param :name
param :age, type: :integer, default: 23
end
params = FlexibleParams.new(name: "Bryce", age: 30, weight: 160, dog: { name: "Bailey", breed: "Shiba Inu" })
params.name #=> "Bryce"
params.age #=> 30
params.weight #=> 160
params.dog.name #=> "Bailey"
params.dog.breed #=> "Shiba Inu"
By default, SimpleAction via SimpleParams will run the execute
method inside of an ActiveRecord transaction. You can modify this setting inside an initializer file.
SimpleAction::Service.transaction = false
If your project is using apipie-rails, then SimpleAction is able to automatically generate the documentation markup for apipie.
api :POST, '/users', "Registers a user"
eval(RegisterUser.api_pie_documentation)
This feature is also delegated to the SimpleParams class. You can read more on the details of that functionality here simple_params.
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request