Skip to content

Commit 7ca5ee9

Browse files
author
LeFnord
committed
issue #582: document file response
- make it ruby 2.3.3 compatible - updates README - adds changelog entry
1 parent 6c96d03 commit 7ca5ee9

File tree

6 files changed

+108
-18
lines changed

6 files changed

+108
-18
lines changed

Diff for: .rubocop_todo.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Metrics/BlockLength:
1818
# Offense count: 3
1919
# Configuration parameters: CountComments.
2020
Metrics/ClassLength:
21-
Max: 265
21+
Max: 275
2222

2323
# Offense count: 12
2424
Metrics/CyclomaticComplexity:

Diff for: CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#### Features
44

5+
* [#583](https://github.com/ruby-grape/grape-swagger/pull/583): Issue #582: document file response - [@LeFnord](https://github.com/LeFnord).
6+
57
* Your contribution here.
68

79
#### Fixes

Diff for: README.md

+35-10
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ add_swagger_documentation \
397397
* [Setting a Swagger default value](#default-value)
398398
* [Response documentation](#response)
399399
* [Changing default status codes](#change-status)
400+
* [File response](#file-response)
400401
* [Extensions](#extensions)
401402

402403

@@ -826,6 +827,32 @@ end
826827
},
827828
```
828829
830+
<a name="file-response" />
831+
#### File response
832+
833+
Set `success` to `File` and sets also produces. If produces wasn't set, it defaults to `application/octet-stream`.
834+
```ruby
835+
desc 'Get a file',
836+
success: File
837+
get do
838+
# your file reponse
839+
end
840+
841+
```
842+
843+
```json
844+
"produces": [
845+
"application/octet-stream"
846+
],
847+
"responses": {
848+
"200": {
849+
"description": "Get a file",
850+
"schema": {
851+
"type": "file"
852+
}
853+
}
854+
}
855+
```
829856

830857
<a name="extensions" />
831858
#### Extensions
@@ -1079,13 +1106,13 @@ role - only admins can see this endpoint.
10791106
<a name="md_usage" />
10801107
## Markdown in Detail (deprecated)
10811108

1082-
Usage of option `markdown` won't no longer be supported,
1109+
Usage of option `markdown` will no longer be supported,
10831110
cause OAPI accepts [GFM](https://help.github.com/articles/github-flavored-markdown) and plain text.
10841111
(see: [description of `Info`](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/2.0.md#info-object))
10851112

10861113

10871114
<a="example" />
1088-
## Example
1115+
## Examples
10891116

10901117
Go into example directory and run it: `$ bundle exec rackup`
10911118
go to: `http://localhost:9292/swagger_doc` to get it
@@ -1106,9 +1133,7 @@ class NamespaceApi < Grape::API
11061133
desc 'Document root'
11071134
get '/' do
11081135
end
1109-
end
11101136
1111-
namespace :hudson do
11121137
desc 'This gets something.',
11131138
notes: '_test_'
11141139
@@ -1117,12 +1142,12 @@ class NamespaceApi < Grape::API
11171142
end
11181143
end
11191144
1120-
namespace :colorado do
1121-
desc 'This gets something for URL using - separator.',
1122-
notes: '_test_'
1123-
1124-
get '/simple-test' do
1125-
{ bla: 'something' }
1145+
namespace :download do
1146+
desc 'download files',
1147+
success: File,
1148+
produces: ['text/csv']
1149+
get ':id' do
1150+
# file response
11261151
end
11271152
end
11281153
end

Diff for: lib/grape-swagger/doc_methods/status_codes.rb

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ def get
88
post: { code: 201, message: 'created {item}' },
99
put: { code: 200, message: 'updated {item}' },
1010
patch: { code: 200, message: 'patched {item}' },
11-
# 200 for delete would only be used, if a success entity is given,
12-
# else it would be set to 204
13-
delete: { code: 200, message: 'deleted {item}' },
11+
delete: { code: 204, message: 'deleted {item}' },
1412
head: { code: 200, message: 'head {item}' },
1513
options: { code: 200, message: 'option {item}' }
1614
}

Diff for: lib/grape-swagger/endpoint.rb

+16-4
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ def description_object(route)
138138
end
139139

140140
def produces_object(route, format)
141+
return ['application/octet-stream'] if file_response?(route.attributes.success) &&
142+
!route.attributes.produces.present?
143+
141144
mime_types = GrapeSwagger::DocMethods::ProducesConsumes.call(format)
142145

143146
route_mime_types = [:formats, :content_types, :produces].map do |producer|
@@ -185,13 +188,14 @@ def response_object(route)
185188

186189
codes.each_with_object({}) do |value, memo|
187190
memo[value[:code]] = { description: value[:message] }
191+
next build_file_response(memo[value[:code]]) if file_response?(value[:model])
188192

189193
response_model = @item
190194
response_model = expose_params_from_model(value[:model]) if value[:model]
191195

192-
if memo.key?(200) && route.request_method == 'DELETE' && value[:model].nil?
193-
memo[204] = memo.delete(200)
194-
value[:code] = 204
196+
if route.request_method == 'DELETE' && !value[:model].nil?
197+
memo[200] = memo.delete(204)
198+
value[:code] = 200
195199
end
196200

197201
next if memo.key?(204)
@@ -201,7 +205,7 @@ def response_object(route)
201205
# TODO: proof that the definition exist, if model isn't specified
202206
reference = { '$ref' => "#/definitions/#{response_model}" }
203207
memo[value[:code]][:schema] = if route.options[:is_array] && value[:code] < 300
204-
{ 'type' => 'array', 'items' => reference }
208+
{ type: 'array', items: reference }
205209
else
206210
reference
207211
end
@@ -235,6 +239,14 @@ def tag_object(route)
235239

236240
private
237241

242+
def file_response?(value)
243+
value.to_s.casecmp('file').zero? ? true : false
244+
end
245+
246+
def build_file_response(memo)
247+
memo['schema'] = { type: 'file' }
248+
end
249+
238250
def partition_params(route)
239251
declared_params = route.settings[:declared_params] if route.settings[:declared_params].present?
240252
required = merge_params(route)

Diff for: spec/issues/582_file_response_spec.rb

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
require 'spec_helper'
2+
3+
describe '#582 respond with a file' do
4+
include_context "#{MODEL_PARSER} swagger example"
5+
6+
let(:app) do
7+
Class.new(Grape::API) do
8+
namespace :issue_582 do
9+
desc 'produces given',
10+
success: File,
11+
produces: ['application/pdf', 'text/csv']
12+
get '/produces_given' do
13+
'responds a file'
14+
end
15+
16+
desc 'automatic produces',
17+
success: 'file'
18+
get '/automatic_produces' do
19+
'responds a file'
20+
end
21+
end
22+
23+
add_swagger_documentation format: :json
24+
end
25+
end
26+
27+
subject do
28+
get '/swagger_doc'
29+
JSON.parse(last_response.body)
30+
end
31+
32+
describe 'produces given' do
33+
let(:produces) { subject['paths']['/issue_582/produces_given']['get']['produces'] }
34+
let(:response) { subject['paths']['/issue_582/produces_given']['get']['responses']['200'] }
35+
36+
specify do
37+
expect(produces).to eql ['application/pdf', 'text/csv']
38+
expect(response).to include 'schema'
39+
expect(response['schema']).to eql 'type' => 'file'
40+
end
41+
end
42+
43+
describe 'automatic_produces' do
44+
let(:produces) { subject['paths']['/issue_582/automatic_produces']['get']['produces'] }
45+
let(:response) { subject['paths']['/issue_582/automatic_produces']['get']['responses']['200'] }
46+
47+
specify do
48+
expect(produces).to eql ['application/octet-stream']
49+
expect(response).to include 'schema'
50+
expect(response['schema']).to eql 'type' => 'file'
51+
end
52+
end
53+
end

0 commit comments

Comments
 (0)