0
我在Rails中創建了一個服務對象來封裝爲Stripe創建計劃的業務邏輯(https://stripe.com/)。 對於服務對象是否有任何好的模式來處理參數驗證?導軌;驗證服務對象中的參數
爲了驗證:
- 我要檢查所有的輸入,零或錯誤的類型。有什麼方法可以輕鬆驗證嗎?也許是軌道延伸?
這裏是一個例子;
# app/services/service.rb
module Service
extend ActiveSupport::Concern
included do
def self.call(*args)
new(*args).call
end
end
end
# app/services/plan/create.rb
class Plan::Create
include Service
attr_reader :params
def initialize(params = {})
@params = params.dup
end
def call
plan = Plan.new(attrs)
return plan unless plan.valid?
begin
external_card_plan_service.create(api_attrs)
rescue Stripe::StripeError => e
plan.errors[:base] << e.message
return plan
end
plan.save
plan.update(is_active: true, activated_at: Time.now.utc)
plan
end
private
def external_card_plan_service
Stripe::Plan
end
def build_data_hash
{
id: params.fetch(:stripe_plan_id)
stripe_plan_id: params.fetch(:stripe_plan_id)
amount: params.fetch(:amount)
currency: params.fetch(:currency)
interval: params.fetch(:interval)
name: params.fetch(:name)
description: params.fetch(:description)
}
end
def attrs
build_data_hash.slice(:stripe_plan_id, :amount, :currency, :interval, :name, :description)
end
def api_attrs
build_data_hash.slice(:id, :amount, :currency, :interval, :name)
end
end
參考文獻:http://brewhouse.io/blog/2014/04/30/gourmet-service-objects。
UPDATE
上面的例子是不那麼複雜。 但是,如果在服務對象中調用服務對象,那麼驗證參數會更好。 CreateUser.call(email_address)
class CreateSubscription
def self.call(plan, email_address, token)
user, raw_token = CreateUser.call(email_address)
subscription = Subscription.new(
plan: plan,
user: user
)
begin
stripe_sub = nil
if user.stripe_customer_id.blank?
customer = Stripe::Customer.create(
source: token,
email: user.email,
plan: plan.stripe_id,
)
user.stripe_customer_id = customer.id
user.save!
stripe_sub = customer.subscriptions.first
else
customer = Stripe::Customer.retrieve(user.stripe_customer_id)
stripe_sub = customer.subscriptions.create(
plan: plan.stripe_id
)
end
subscription.stripe_id = stripe_sub.id
subscription.save!
rescue Stripe::StripeError => e
subscription.errors[:base] << e.message
end
subscription
end
end
而且我嘗試使用了Virtus(https://github.com/solnic/virtus)。 但是我不知道如何在這種類型的服務對象中使用它。
UPDATE
# api/v1/controller/plans_controller.rb
module Api
module V1
class PlansController < Api::V1::ApiController
before_action :check_type, only: [:create]
def create
@result = Plan::Create.call(plan_info_params)
if @result.errors.blank?
resource = Api::V1::PlanResource.new(@result, nil)
# NOTE: Include all domains created within this routine.
serializer = JSONAPI::ResourceSerializer.new(Api::V1::PlanResource)
json_body = serializer.serialize_to_hash(resource)
render json: json_body, status: 201 # :ok
else
errors = jsonapi_errors(@result)
response = { errors: errors }
render json: response, status: 422 # :unprocessable_entity
end
end
private
def check_type
data_type = 'plans'
unless params.fetch('data', {}).fetch('type', {}) == data_type
render json: { errors: [{ title: 'Unprocessable Entity', detail: "Type must be #{data_type}" }] }, status: 422
end
end
def plan_info_params
params.require(:data).require(:attributes).permit(:stripe_plan_id, :amount, :currency, :interval, :name, :description)
end
end
end
end
感謝您的回答。那麼這裏Form對象是否正確使用?此外,我不確定Form對象是否會好,因爲我們一直在構建API。 – Tosh
@TSH表格用於進一步處理的驗證和準備參數。所以是的,表單對象是一個很好的選擇,不管它是否適用於API。 –
謝謝!你如何看待virtus +表單對象?我很想知道優點和缺點。 – Tosh