如何编写RSwag Spec实现GET请求传参至Rails控制器?
问题
如何编写RSwag Spec,让GET请求能将my_field: 'my_value'传入控制器的params中?
初始尝试
路由配置(config/routes.rb)
Rails.application.routes.draw do namespace :api do resources :my_tests end end
控制器代码(app/controllers/api/my_tests_controller.rb)
class Api::MyTestsController < Api::BaseController def index render json: do_something_with(params) # 期望`params[:my_field] == 'my_value'` end end
初始RSwag测试代码(spec/api/my_tests/index_spec.rb)
RSpec.describe 'Test', type: :request do context 'on openapi spec' do let(:Authorization) { bearer_token } path '/api/my_tests' do get 'Test' do consumes 'application/json' produces 'application/json' security [bearerAuth: {}] parameter name: :my_field, in: :body, type: :string response '200', 'Test' do let(:my_field) { 'my_value' } run_test! end end end end end
运行后得到的params不符合预期:
{ "\"my_value\"": nil, controller: "api/my_tests", action: "index", my_test: {} }
尝试复用POST请求的解决方案
之前找到的适用于POST请求的参数配置方案,放到GET请求里完全不起作用。修改后的测试代码如下:
RSpec.describe 'Test', type: :request do context 'on openapi spec' do let(:Authorization) { bearer_token } path '/api/my_tests' do get 'Test' do consumes 'application/json' produces 'application/json' security [bearerAuth: {}] parameter name: :body, in: :body, schema: { type: :object, properties: { my_field: { type: :string }, }, } response '200', 'Test' do let(:body) { { my_field: 'my_value' } } run_test! end end end end end
结果生成的params还是不对:
{ "{\"my_field\":\"my_value\"}": nil, controller: "api/my_tests", action: "index", my_test: {} }
但如果把请求改成POST,就能得到完全符合预期的params:
{ "my_field": "my_value", # <- 这是期望获取的字段 "controller": "api/my_tests", "action": "foo", "my_test": { "my_field": "my_value" } }
正确解决方案
方案1:遵循HTTP规范,使用URL查询参数(推荐)
GET请求的参数本来就应该放在URL的查询字符串里,而非请求体中,这是HTTP的规范约定,RSwag对GET请求的body参数处理逻辑也和POST完全不同。只需要把测试里的参数位置改成:query即可:
RSpec.describe 'Test', type: :request do context 'on openapi spec' do let(:Authorization) { bearer_token } path '/api/my_tests' do get 'Test' do produces 'application/json' security [bearerAuth: {}] # 将参数放到query中 parameter name: :my_field, in: :query, type: :string response '200', 'Test' do let(:my_field) { 'my_value' } run_test! end end end end end
这样控制器里的params[:my_field]就能正确获取到'my_value',最终生成的params会是:
{ "my_field": "my_value", controller: "api/my_tests", action: "index" }
方案2:强制给GET请求加请求体(不推荐)
如果业务上确实需要GET请求带请求体(强烈不建议,因为很多HTTP客户端和服务器对这种情况的处理不一致,容易出现兼容性问题),可以手动在测试里设置请求体,并指定内容类型:
RSpec.describe 'Test', type: :request do context 'on openapi spec' do let(:Authorization) { bearer_token } path '/api/my_tests' do get 'Test' do consumes 'application/json' produces 'application/json' security [bearerAuth: {}] response '200', 'Test' do before do # 手动设置请求body和内容类型 request.body = { my_field: 'my_value' }.to_json request.content_type = 'application/json' end run_test! end end end end end
内容的提问来源于stack exchange,提问作者Augustinas
相关产品推荐
相关产品推荐

