Rails API 项目里,如果请求的参数个数较多,需要验证的类型也比较复杂且各个请求之间差异也比较大,在 server 里用什么架构去验证比较好?

realwol · 发布于 2016年12月14日 · 最后由 yingce 回复于 2016年12月19日 · 1017 次阅读
4933

一般的,可以用routes,callback或者在方法中来简单验证。如果是碰到如题的这种环境,怎么做比较好?
像grape一样的参数校验应该也算是额外封装了一个步骤去验证每个api的请求是否合理吧。
或者还有什么比较好的办法实现? gem也可以,说出来相互拓展一下思路。

共收到 33 条回复
19106

可以看下ruby-china api下的base_controller 非常漂亮易懂

或者看下rails_param

15815

很多人批评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逻辑

20859

#2楼 @novtopro 见过所有的api请求全部先进同一个controller进行一些处理,然后再redirect_to到相应的controller,感觉没有你这个办法好。

17671

接口还是以资源(model)为单位会好管理一些吧

27

rails_param 这个 gem 有些小 bug,而且已经没人维护了

19106

#3楼 @adamshen 这个有点像taobao或者百度的那种微服务接口吧

4933

#3楼 @adamshen 之前有过将参数存入表中,然后根据方法和参数关系,调用起来一次检查,等于多一层服务出来专门做这个事情。这样的做可以将方法的维护和文档关联起来,文档先行,对于大型的复杂应用还是挺有用的。不过一般情况下,不是很建议这样做,因为项目达到这种程度,应该是可以通过分割或者抽取来进行简化。

20859

#6楼 @yingce 没有实际用过微服务,不是很了解。我想应该就是像楼上说的,当项目需要的动态路由、参数检查、权限控制复杂度很高的情况下,再抽象出一层服务来单独做这些事情比较合适。

4933

#2楼 @novtopro 给点参考链接,光这么说很难领会。

15815

@realwol

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
4933

#12楼 @novtopro 可行,不过validation 似乎需要单独文件,对文件名有特殊要求吗?维护起来代价大吗?

15815
  1. 需要单独的文件
  2. 文件名按照约定来,Rails强调的不也是Convention over Configuration嘛
  3. 当然需要维护,也不算大。

因为我目前也是按照JSON API规范去构建API,我Explore了一下其它的参数校验清洗gem,包括strong_parameters, rails_param感觉都不是很满意,hanami-validation和dry-validation的逻辑表达能力实在太好了,于是就用了。

其实我也不知道这种方式好不好,不过就目前来看也还OK

15815

如果只要求简单的校验清洗,我觉得就没有必要搞那么复杂。

4933

#15楼 @novtopro 是,简单的可以不去讨论,所以就当我题目中说的那种请求类型是个讨论前提。
rails_params 这种实现方式你是有什么顾虑还是觉得哪儿的设计不满意?我倒是感觉挺好哈。各有所爱吧。

4933

#1楼 @yingce 我在我之前fork的ruby china项目里没找到base controller啊,是更新了还是有单独api项目?

19106

#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
4933

#18楼 @yingce 能麻烦你发我一下项目地址吗?👄

6764

Rails 写接口的话, 可以试一下 apipie 呢

11524

和strong parameter一样,为不同的验证需求设计private method。 controller 臃肿的话作为concern 独立出去。或者扔model里面也ok?

我第一个想到的是phoenix的 changeset。

4933

#11楼 @Rei 说实话,光这网站,看着就比其他的高端。

4933

#21楼 @42thcoder 这个更偏向于文档生成和管理吧。

4933

#20楼 @yingce #25楼 @42thcoder 还有个我认为比较重要的问题就是 错误信息的定制,你们说的这两个我没有深入的用过,不太清楚如何定制,不过据我所知,grape也是最近的版本里才加入的。不知道两位对这方面有了解吗?

845

api-pipe 可以验证类型和时候缺失。

4933

#27楼 @bastengao 支持错误信息定制不

845

#28楼 @realwol 支持么,有不同的错误码和消息。我跑个砖,剩下你自己看吧。

4933

#29楼 @bastengao 那还不错 有啥不好的地方没

845

#30楼 @realwol 用的人相对较少。我用的比较浅,我们的 API 也比较简单。

4933

#31楼 @bastengao 楼上有人说了 我看了下 有机会试试

19106

#26楼 @realwol 你可以花5分钟看看源码, 传参数的错误就那几种,每个定义一下就可以了

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册