乐趣区

关于segmentfault:框架时代终结者使用Grape快速开发API

作者:Run,总架构师
工作教训 5 年,以后就任行业出名技术公司,负责总架构师职位,善于前后端技术栈,Ruby、Python、JavaScript 等语言。

内容目录

  • 针对 Grape 框架的改良

    • 深层 expose
    • 接口返回值申明
    • 参数、返回值一体化
    • 针对测试的改良
  • 老手如何上手
  • 理念

    • 面向文档的开发
    • 你真的不须要 Controller 测试吗?
  • 写在最初

针对 Grape 框架的改良

深层 expose

你兴许晓得,expose 能够嵌套。如果传递的是个不带参的块,则会执行嵌套渲染:

class Entities::Article < Grape::Entity
 expose :user do
 expose :name {|article| article.user.name}
 expose :age {|article| article.user.age}
 end
end

如上,会渲染一个如下的数据结构:

{
 "user": {
 "name": "Jim",
 "age": 18
 }
}

如果此时传入 deep: true,则嵌套层绑定的 instance 就不一样了。上面的例子与下面的例子展现了同样的成果:

class Entities::Article < Grape::Entity
 expose :user, deep: true do
 expose :name
 expose :age
 end
end

接口返回值申明

status 用于申明接口的返回值(successfailentity 是非凡状况下的别名)。它有如下几种根本的调用模式:

status 200 do
 expose :article, using: Entities::Article
end
​
status 200, '返回文章数据' do
 expose :article, using: Entities::Article
end
​
status 400, '申请参数有误' do
 expose :code, desc: '错误码'
 expose :message, desc: '谬误音讯'
end
​
success '申请胜利' do
 expose :article, using: Entities::Article
end
​
fail '申请失败' do
 expose :code, desc: '错误码'
 expose :message, desc: '谬误音讯'
end
​
entity do
 expose :article, using: Entities::Article
end

上述申明次要起两个作用:

  1. 在接口逻辑中调用 present 办法不必显示地指定 Entity 类型,它是主动解析的。

    以前,你必须这样调用:

    present :article, article, with: Entities::Article

    当初,只用这样:

    present :article, article

    因为在 status 申明中它曾经晓得如何渲染 article 实体了。

  2. status 申明可对应生成文档。

参数、返回值一体化

Grape::Entity 新加一个 to_params 办法,使得你能够在参数申明中反复利用:

params do
 requires :article, type: Hash do
 optional :all, using: Entities::Article.to_params
 end
end

它比 Grape::Entity.documentation 更好用,做了如下改良:

  1. type 能够写成字符串:
  expose :foo, documentation: {type: 'string'}
  1. 可混用额定参数,如同时指定 param_type 参数:
  expose :foo, documentation: {param_type: 'body'}
  1. 正当解决了 is_array
 expose :bar, documentation: {type: String, is_array: true}

针对测试的改良

当初能够用编程 style 的形式测试接口的返回值了,不须要再测试诸如 JSON 字符串、XML 文本之类的。如果像上面这样实现接口:

present :article, article

就能够像上面这样测试:

get '/article/1'
assert_equal 200, last_response.status
assert_equal articles(:one), presents(:article)

留神,这个性能不是实现在框架中的,须要克隆脚手架我的项目:

git clone https://github.com/run27017/grape-app-demo.git

老手如何上手

如果你是齐全的老手,倡议先从相熟 Grape 框架开始。我建议您浏览我仓库下的文档。在您相熟了 Grape 框架当前,再浏览以上我对 Grape 框架改良的局部。对于整个框架的设计理念,可浏览后文。

我的项目上手就从我提供的脚手架我的项目开始,所有性能都集成进来了:

git clone https://github.com/run27017/grape-app-demo.git

理念

面向文档的开发

当今环境下,有许多的开发范式供后端开发者抉择,例如_测试驱动开发_、_行为驱动开发_、_麻利软件开发_等等。与之绝对的,我提出了一个新的想法,我将其称为_面向文档的开发_。

写 API 我的项目的同时是要筹备文档的。我不晓得大家是如何筹备文档的,但往往都逃不出一个怪圈:同一个接口,我的实现要写一份,我的文档也要同时写一份。我经常在想,为什么我在写接口的同时不能将文档同步地实现呢?换个角度想,接口文档的契约精力为何不能主动地成为实现的一部分?如果,我能创造一个 DSL,在编写文档的同时就可能制约接口的行为,那不正是我想要的吗?

说干就干!

我发现 Grape 框架就曾经提供了相似的 DSL 了。例如你在制订参数时能够像这样:

params do
 requires :user, type: Hash do
 requires :name, type: String, desc: '用户的姓名'
 requires :age, type: Integer, desc: '用户的年龄'
 end
end

下面的代码就能够对参数进行制约,限度参数为 nameage 两个字段,并别离限度它们的类型为 StringInteger. 与此同时,一个名为 grape-swagger 的库能够将 params 的宏定义渲染成 Swagger 文档的一部分。完满,文档和实现在这里联合了。

另外,Grape 框架提供了 desc 宏,它是一个纯文档的申明供第三方库读取,不会对接口行为产生任何影响。

desc '创立新用户' do
 tags 'users'
 entity Entities::User
end

然而,毕竟 Grape 框架不是齐全的面向文档的开发框架,它有很多重要的使命,所以它和文档的无缝连接也就仅限于此了。你能看到,params 宏是个完满联合的范例,desc 宏很惋惜只与文档渲染无关,而后就别无其他了。

鉴于 Grape 框架是个开源框架,批改它以增加几个小整机还是很繁难的一件事。我用了几天的工夫增加了一个 status 宏,能够用它来申明返回值:

status 200 do
  expose :user, deep: true do
    expose :id, documentation: {type: Integer, desc: '用户的 id'}
    expose :name, documentation: {type: String, desc: '用户的姓名'}
    expose :age, documentation: {type: Integer, desc: '用户的年龄'}
  end
end

上述申明次要起两个作用:

  1. 在接口逻辑中调用 present 办法不必显示地指定 Entity 类型,它是主动解析的。

    以前,你必须这样调用:

    present :user, user, with: Entities::User

    当初,只用这样:

    present :user, user

    因为在 status 申明中它曾经晓得如何渲染 user 实体了。

  2. grape-swagger 库能够解析 status 宏生成文档。

所有还只是冰山一角。

你真的不须要 Controller 测试吗?

无关接口的单元测试,有两个观点争论不休:接口测试应该是针对 Integration 测试还是 Controller 测试?Integration 测试像是一个黑匣子,开发者调用接口,而后针对接口返回的视图进行测试。而 Controller 测试也会一样地调用接口,但会测到外部的状态。

通过上面的两个案例直观地感受一下 Controller 测试和 Integration 测试在 Rails 框架中的不同写法。

在晚期的 Rails 版本中,是有 Controller 测试的:

class ArticlesControllerTest < ActionController::TestCase
  test "should get index" do
    get :index
    assert_response :success
    assert_equal users(:one, :two, :three), assigns(:articles)
  end
end

Rails 5 当前,更举荐 Integration 测试:

class ArticlesControllerTest < ActionDispatch::IntegrationTest
 test "should get index" do
 get articles_url
 assert_response :success
 end
end

留神到 Integration 测试中是没有对应的 assert_equal 语句的,因为它比拟难写。如果视图返回的是 JSON 数据,能够尝试用上面的等效写法:

assert_equal users(:one, :two, :three).as_json, JSON.parse(last_response.body)

然而测试视图的代码及其依赖视图的变动,也会经常性的生效,下面只是尝试性的一种写法而已。

我不想在这里探讨 Controller 测试和 Integration 测试到底孰优孰劣的问题,只管你可能曾经从字里行间察觉到我的倾向性。对于这个话题可能从 2012 年探讨到 2020 年,不信你能够看这个帖子。我可不想让状况变得更糟。很屡次我在想,那些拥护 Controller 测试的人可能仅仅把 Controller 的实例变量看成是其外部状态而已,而没有意识到它也是 Controller 与 Template 之间的契约。这不怪他们,因为用传递实例变量的形式定义契约的确不够优雅。

好在我做了一些简略的工作,让其在 Grape 框架内能够更优雅地测试接口的返回。你只须要在逻辑接口中应用 present 办法指定渲染数据:

present :users, users

而后就能够在测试用例中联合非凡的 presents 办法测试它:

assert_equal users(:one, :two, :three), presents(:users)

assigns 很像,然而它更难受不是么?

写在最初

这就是我对 Grape 框架的革新过程,曾经开始并将继续上来。我的革新理念无外乎两个想法:更好的文档联合和更好的测试。而事实上,只须要一点点工作,的确就能够起作用了。

如果你也想用到我所革新的 Grape 框架,间接克隆我的脚手架就好了:

git clone https://github.com/run27017/g…

脚手架中应用的是我 Fork 后的框架集,它们是:

  • grape
  • grape-entity
  • grape-swagger

点击它们的链接看一看吧,兴许你也能成为开源世界的贡献者呢。

举荐

如果想理解学习更多能够看我最新录制的课程

课程链接:https://ke.sifou.com/course/1…

设计这门课的初衷
  • 以后 Web 开发的支流模式:前后端拆散
  • Web API 开发,没有必要形形色色,应采纳最佳实际
  • 将本人多年的实际经验总结并分享
这门课在讲什么?
  • 遵循规范:最小诧异准则
  • 接口的齐备性:输出和输入、鉴权、错误处理等
  • 与框架整合
为什么每个人都应该有一套本人的脚手架?
  1. 框架只是通用模版的提供者,并没有安顿具体的解决方案
  2. 框架并没有细化到最佳实际
退出移动版