Grape API validation
Bài đăng này đã không được cập nhật trong 8 năm
Việc sử dụng gem Grape
trong rails
đôi khi cần đến việc validation params
, một vài tip nhỏ hi vọng giúp bạn chủ động hơn trong việc xử lý validation
.
Link về gem Grape: https://github.com/ruby-grape/grape
Validation
trong Grape
có nhiều phần khác nhau, validation
params là việc bắt validation
tại đầu vào params
của API.
Ta thường có:
resources :order do
params do
requires :mode, type: Integer, values: [0, 1]
optional :okan_info, type: Hash do
optional :okan_id, type: String, max_length: 255, allow_blank: false
optional :nominate_flg, type: Boolean
end
requires :start_time, type: DateTime, coerce_with: ->(val){Time.zone.parse(val).to_datetime.utc}
requires :job_kind, type: Array[String]
requires :absence_flg, type: Boolean
optional :repeat_pattern, type: Integer
optional :coupon_id, type: Integer
optional :notice_time, type: Integer, values: Settings.orders.notice_time
requires :work_time, type: Integer,
values: [*Settings.orders.min_work_time..Settings.orders.max_work_time]
end
...
end
Muốn hạn chế gía trị của params
ta dùng values
. (https://github.com/ruby-grape/grape#parameter-validation-and-coercion)
Muốn convert gía trị của params
ta dùng coerce_with
. (https://github.com/ruby-grape/grape#custom-types-and-coercions)
Tại ví dụ ta thấy có requires :start_time, type: DateTime, coerce_with: ->(val){Time.zone.parse(val).to_datetime.utc}
, ý nghĩa của đọa code này là parse
gía trị của start_time
về gía trị utc
.
Việc sử dụng coerce_with
cần được catch
bằng cách check message_key
của error
rescue_from Grape::Exceptions::ValidationErrors do |e|
e.each do |_param, errors|
case errors[:message_key]
...
when :coerce
...
else
...
end
end
end
Muốn tạo thêm 1 dạng validation
mới, chỉ cần địng nghĩa thêm 1 class
module APIValidation
class MaxLength < Grape::Validations::Base
def validate_param! attr_name, params
return if params[attr_name].nil? || params[attr_name].try(:length).try(:<=, (@option))
raise Grape::Exceptions::Validation,
params: [@scope.full_name(attr_name)],
headers: Settings.api_validation.bad_digit_params
end
end
end
Đây là validation max_length
cho độ dài params
là string, sử dụng như những validation
khác: optional :okan_id, type: String, max_length: 255, allow_blank: false
.
validate_param!
là method
của Grape::Validations::Base
:
module Grape
...
module Validations
class CoerceValidator < Base
def initialize(*_args)
super
(@converter = Types.build_coercer(type, (@option[:method])))
end
def validate_param!(attr_name, params)
raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:coerce) unless params.is_a? Hash
new_value = coerce_value(params[attr_name])
raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:coerce) unless valid_type?(new_value)
params[attr_name] = new_value
end
end
end
end
Ở đây ta kế thừa lại class
Grape::Validations::Base
và override lại hàm validate_param!
.
Đoạn code headers: Settings.api_validation.bad_digit_params
dùng để mark
lại dạng error
và lưu tại headers
, khi catch
lại thì lấy ra như đối với message_key
.
Muốn thêm validation
có liên hệ giữa các params
với nhau, cũng làm tương tự cách trên, gỉa sử params
đầu vào có search_start_time, search_start_time
, và điều kiện là search_end_time - search_start_time >= 100.days
.
params do
optional :search_start_time, type: Date
optional :search_end_time, type: Date, greater_than: [:search_start_time, 100]
all_or_none_of :search_start_time, :search_end_time
end
Tại module
định nghĩa error
class GreaterThan < Grape::Validations::Base
def validate_param! attr_name, params
return if params[attr_name].nil? ||
params[attr_name].try( :>=, params[@option[0]] + (@option[1].days))
raise Grape::Exceptions::Validation,
params: [@scope.full_name(attr_name)],
headers: Settings.api_validation.bad_format_params
end
end
Đoạn code greater_than: [:search_start_time, 100]
truyền các gía trị cần so sánh vào @option
khi kiểm tra validate
tại hàm validate_params
: return if params[attr_name].nil? || params[attr_name].try( :>=, params[@option[0]] + (@option[1].days))
Ta có thể custom lại các validation
như all_or_none_of
, at_least_one_of
... bằng cách định nghĩa lại:
class AllOrNoneOfValidator < Grape::Validations::MultipleParamsBase
def validate! params
...
end
end
Chú ý Grape::Validations::MultipleParamsBase
là class base
cho việc validate
multiple params
, tuy nhiên cách này không nên sử dụng tùy tiện vì ảnh hưởng đến hàm chuẩn trong Grape
.
Cảm ơn và hi vọng bài viết gíup ích phần nào trong công việc của bạn.
All rights reserved