一般的,可以用 routes,callback 或者在方法中来简单验证。如果是碰到如题的这种环境,怎么做比较好?
像 grape 一样的参数校验应该也算是额外封装了一个步骤去验证每个 api 的请求是否合理吧。
或者还有什么比较好的办法实现?gem 也可以,说出来相互拓展一下思路。
很多人批评 hanami 将一个 action 独立成一个类的方式,但这其实赋予了 action 更大的灵活性。使用 rails_param,你的 action 很快就会充满各种参数过滤清洗逻辑,当然,你可以对其进行抽取分离,但是效果也并不是很好。反观 hanami-validation,一方面参数过滤清晰表达能力更强,另一方面能够跟 action 的逻辑进行有效分离。
推荐 hanami-validation 或者 dry-validation (其实他们是一伙的),至于怎样整合进入 Rails,我目前是在 application_controller 里面加入一个 before_action, 根据对应的 controller+action 按照某种约定查找对应的 validation,暴露一个 sanitized_params helper 方法给后续的 action 逻辑
ApplicationController
class Api::BaseController < ActionController::API
before_action :sanitize
helper_method :sanitized_params
private
def sanitized_params
@sanitized_params ||= begin
sanitizer ? sanitization.output : request.parameters
end
end
def sanitize
render_errors(sanitization.messages, :bad_request) && return if sanitization && sanitization.failure?
end
def sanitization
@sanitization ||= sanitizer ? sanitizer.call(request.parameters.to_h) : nil
end
def sanitizer
@sanitizer ||= begin
controller_without_suffix = request.controller_class.to_s.match(/^(.*)Controller$/)[1]
action = params[:action].titleize
"#{controller_without_suffix}::#{action}Validation".safe_constantize
end
end
end
A simple sanitizer: Posts::IndexValidation
class Api::V1::Posts::IndexValidation < Api::V1::Validation
validations do
optional(:sort).filled
optional(:filter).filled
optional(:page).schema do
optional(:number).filled
optional(:size).filled
end
end
end
PostsController
class Api::V1::PostsController < Api::BaseController
def index
# Use sanitized_params here
end
end
因为我目前也是按照 JSON API 规范去构建 API,我 Explore 了一下其它的参数校验清洗 gem,包括 strong_parameters, rails_param 感觉都不是很满意,hanami-validation 和 dry-validation 的逻辑表达能力实在太好了,于是就用了。
其实我也不知道这种方式好不好,不过就目前来看也还 OK
#17 楼 @realwol 记错了 是 api/v3/application_controller
https://github.com/ruby-china/homeland/blob/master/app/controllers/api/v3/application_controller.rb
在 controller 使用
optional! :offset, default: 0
optional! :limit, default: 20, values: 1..150
和 strong parameter 一样,为不同的验证需求设计 private method。controller 臃肿的话作为 concern 独立出去。或者扔 model 里面也 ok?
我第一个想到的是 phoenix 的 changeset。
#20 楼 @yingce #25 楼 @42thcoder 还有个我认为比较重要的问题就是 错误信息的定制,你们说的这两个我没有深入的用过,不太清楚如何定制,不过据我所知,grape 也是最近的版本里才加入的。不知道两位对这方面有了解吗?