Add a macro for complexes multiparts

This will allow to describe multipart in a short way, like JSON payload:

Before:

    put 'Creates a blog with thumbnail' do
      consumes 'multipart/form-data'
      parameter name: :title, in: :formData, type: :string, required: true
      parameter name: :content, in: :formData, type: :string, required: true
      parameter name: :file, in: :formData, type: :file, required: true

      let(:blog) { FactoryBot.build(:blog) }
      let(:title) { blog.title }
      let(:content) { blog.content }
      let(:file) { blog.file }

      ...
    end

After:

    put 'Creates a blog with thumbnail' do
      consumes 'multipart/form-data'
      parameter name: :blog, in: :formData, schema: { '$ref' => '#/definitions/blog' }

      let(:blog) { FactoryBot.attributes_for(:blog) }

      ...
    end

Your mileage may vary but you can always choose the best option.
This commit is contained in:
Gabriel Sobrinho 2020-04-16 22:00:55 -03:00
parent 7ceedab4cb
commit f8dbd98bbc
No known key found for this signature in database
GPG Key ID: 2FD82B66C9E08620
7 changed files with 110 additions and 1 deletions

View File

@ -185,8 +185,22 @@ module Rswag
# Rather that serializing with the appropriate encoding (e.g. multipart/form-data),
# Rails test infrastructure allows us to send the values directly as a hash
# PROS: simple to implement, CONS: serialization/deserialization is bypassed in test
smart_payload = build_smart_form_payload(parameters, example)
raw_payload = build_raw_form_payload(parameters, example)
smart_payload.merge(raw_payload)
end
def build_smart_form_payload(parameters, example)
smart_tuples = parameters
.select { |p| p[:in] == :formData && p[:schema] }
.map { |p| example.send(p[:name]) }
.reduce({}, :merge)
end
def build_raw_form_payload(parameters, example)
tuples = parameters
.select { |p| p[:in] == :formData }
.select { |p| p[:in] == :formData && !p[:schema] }
.map { |p| [p[:name], example.send(p[:name])] }
Hash[tuples]
end

View File

@ -178,6 +178,20 @@ module Rswag
)
end
end
context 'smart form payload' do
before do
metadata[:operation][:consumes] = ['multipart/form-data']
metadata[:operation][:parameters] = [{ name: 'comment', in: :formData, schema: { type: 'object' } }]
allow(example).to receive(:comment).and_return(text: 'Some comment')
end
it 'sets payload to hash of names and example values' do
expect(request[:payload]).to eq(
:text => 'Some comment'
)
end
end
end
context 'produces content' do

View File

@ -8,6 +8,12 @@ class BlogsController < ApplicationController
respond_with @blog
end
# POST /blogs/multipart
def multipart_create
@blog = Blog.create(params.require(:blog).permit(:title, :content))
respond_with @blog
end
# POST /blogs/flexible
def flexible_create

View File

@ -1,5 +1,6 @@
TestApp::Application.routes.draw do
post '/blogs/multipart', to: 'blogs#multipart_create'
post '/blogs/flexible', to: 'blogs#flexible_create'
post '/blogs/alternate', to: 'blogs#alternate_create'
resources :blogs

View File

@ -7,6 +7,7 @@ RSpec.feature 'swagger-ui', js: true do
expect(page).to have_content('GET /blogs Searches blogs', normalize_ws: true)
expect(page).to have_content('POST /blogs Creates a blog', normalize_ws: true)
expect(page).to have_content('POST /blogs/multipart Creates a blog using multipart', normalize_ws: true)
expect(page).to have_content('GET /blogs/{id} Retrieves a blog', normalize_ws: true)
end
end

View File

@ -49,6 +49,33 @@ RSpec.describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
end
end
path '/blogs/multipart' do
post 'Creates a blog using multipart' do
tags 'Blogs'
description 'Creates a new blog from provided data'
operationId 'createBlogWithMultipart'
consumes 'multipart/form-data'
produces 'application/json'
parameter name: :blog, in: :formData, schema: { type: :object, properties: { name: :blog, type: :object, properties: { '$ref' => '#/definitions/blog' } } }
let(:blog) { { blog: { title: 'foo', content: 'bar' } } }
response '201', 'blog created' do
# schema '$ref' => '#/definitions/blog'
run_test!
end
response '422', 'invalid request' do
schema '$ref' => '#/definitions/errors_object'
let(:blog) { { blog: { title: 'foo' } } }
run_test! do |response|
expect(response.body).to include("can't be blank")
end
end
end
end
path '/blogs/flexible' do
post 'Creates a blog flexible body' do
tags 'Blogs'

View File

@ -155,6 +155,52 @@
}
}
},
"/blogs/multipart": {
"post": {
"summary": "Creates a blog using multipart",
"tags": [
"Blogs"
],
"description": "Creates a new blog from provided data",
"operationId": "createBlogWithMultipart",
"parameters": [
],
"responses": {
"201": {
"description": "blog created",
"content": {
}
},
"422": {
"description": "invalid request",
"content": {
"application/json": {
"schema": {
"$ref": "#/definitions/errors_object"
}
}
}
}
},
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"name": "blog",
"type": "object",
"properties": {
"$ref": "#/definitions/blog"
}
}
}
}
}
}
}
},
"/blogs/flexible": {
"post": {
"summary": "Creates a blog flexible body",