Skip to content

Commit e1201dd

Browse files
author
Tim Vandecasteele
committed
Merge branch 'pr/54'
2 parents a65838f + 6159b33 commit e1201dd

File tree

7 files changed

+139
-6
lines changed

7 files changed

+139
-6
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ source "http://rubygems.org"
44
# gem "activesupport", ">= 2.3.5"
55

66
gem 'grape', '>= 0.2.0'
7+
gem 'grape-entity', '~> 0.3.0'
78
gem 'kramdown'
89

910
# Add dependencies to develop your gem here.

Gemfile.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ GEM
2020
rack-accept
2121
rack-mount
2222
virtus
23+
grape-entity (0.3.0)
24+
activesupport
25+
multi_json (>= 1.3.2)
2326
hashie (2.0.5)
2427
i18n (0.6.1)
2528
jeweler (1.8.4)
@@ -71,6 +74,7 @@ PLATFORMS
7174
DEPENDENCIES
7275
bundler (> 1.0.0)
7376
grape (>= 0.2.0)
77+
grape-entity (~> 0.3.0)
7478
jeweler (~> 1.8.4)
7579
kramdown
7680
pry

README.markdown

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ module API
3333
end
3434
```
3535

36-
To explore your API, either download [Swagger UI](https://github.com/wordnik/swagger-ui) and set it up yourself or go to the [online swagger demo](http://petstore.swagger.wordnik.com/) and enter your localhost url documentation root in the url field (probably something in the line of http://localhost:3000/swagger_doc.json).
36+
To explore your API, either download [Swagger UI](https://github.com/wordnik/swagger-ui) and set it up yourself or go to the [online swagger demo](http://petstore.swagger.wordnik.com/) and enter your localhost url documentation root in the url field (probably something in the line of http://localhost:3000/swagger_doc.json).
3737
If you use the online demo, make sure your API supports foreign requests by enabling CORS in grape, otherwise you'll see the API description, but requests on the API won't return. You can do this by putting below code in your Grape API definition:
3838

3939
```` ruby
@@ -53,23 +53,54 @@ You can pass a hash with some configuration possibilities to ```add_swagger_docu
5353

5454
## Swagger Header Parameters
5555

56-
Swagger also supports the documentation of parameters passed in the header. Since grape's ```params[]``` doesn't return header parameters we can
56+
Swagger also supports the documentation of parameters passed in the header. Since grape's ```params[]``` doesn't return header parameters we can
5757
to specify header parameters seperately in a block after the description.
5858

5959
``` ruby
6060
desc "Return super-secret information", {
6161
headers: {
6262
"XAuthToken" => {
6363
description: "Valdates your identity",
64-
required: true
64+
required: true
6565
},
6666
"XOptionalHeader" => {
6767
description: "Not reallly needed",
68-
required: false
68+
required: false
6969
}
7070
}
7171
}
7272
```
73+
### Grape Entities
74+
75+
Add the [grape-entity](https://github.com/agileanimal/grape-entity) gem to our Gemfile.
76+
Please refer to the [grape-entity documentation](https://github.com/gileanimal/grape-entity/blob/master/README.markdown)
77+
for more details.
78+
79+
The following example exposes statuses. And exposes statuses documentation adding :type and :desc.
80+
81+
```ruby
82+
module API
83+
84+
module Entities
85+
class Status < Grape::Entity
86+
expose :text, :documentation => { :type => "string", :desc => "Status update text." }
87+
end
88+
end
89+
90+
class Statuses < Grape::API
91+
version 'v1'
92+
93+
desc 'Statuses index', {
94+
:entity => API::Entities::Status
95+
}
96+
get '/statuses' do
97+
statuses = Status.all
98+
type = current_user.admin? ? :full : :default
99+
present statuses, with: API::Entities::Status, :type => type
100+
end
101+
end
102+
end
103+
```
73104

74105
## Swagger additions
75106
grape-swagger allows you to add an explanation in markdown in the notes field. Which would result in proper formatted markdown in Swagger UI. The default Swagger UI doesn't allow HTML in the notes field, so you need to use an adapted version of Swagger UI (you can find one at https://github.com/tim-vandecasteele/swagger-ui/tree/vasco).

grape-swagger.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Gem::Specification.new do |s|
4848

4949
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
5050
s.add_runtime_dependency(%q<grape>, [">= 0.2.0"])
51+
s.add_runtime_dependency(%q<grape-entity>, ["~> 0.3.0"])
5152
s.add_runtime_dependency(%q<kramdown>, [">= 0"])
5253
s.add_development_dependency(%q<shoulda>, [">= 0"])
5354
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])

lib/grape-swagger.rb

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ def self.setup(options)
4141
:api_version => '0.1',
4242
:markdown => false,
4343
:hide_documentation_path => false,
44-
:hide_format => false
44+
:hide_format => false,
45+
:models => []
4546
}
4647
options = defaults.merge(options)
4748

@@ -84,10 +85,12 @@ def self.setup(options)
8485
get "#{@@mount_path}/:name" do
8586
header['Access-Control-Allow-Origin'] = '*'
8687
header['Access-Control-Request-Method'] = '*'
88+
models = []
8789
routes = @@target_class::combined_routes[params[:name]]
8890
routes_array = routes.map do |route|
8991
notes = route.route_notes && @@markdown ? Kramdown::Document.new(strip_heredoc(route.route_notes)).to_html : route.route_notes
9092
http_codes = parse_http_codes route.route_http_codes
93+
models << route.route_entity if route.route_entity
9194
operations = {
9295
:notes => notes,
9396
:summary => route.route_description || '',
@@ -96,20 +99,23 @@ def self.setup(options)
9699
:parameters => parse_header_params(route.route_headers) +
97100
parse_params(route.route_params, route.route_path, route.route_method)
98101
}
102+
operations.merge!({:responseClass => route.route_entity.to_s.split('::')[-1]}) if route.route_entity
99103
operations.merge!({:errorResponses => http_codes}) unless http_codes.empty?
100104
{
101105
:path => parse_path(route.route_path, api_version),
102106
:operations => [operations]
103107
}
104108
end
105109

106-
{
110+
api_description = {
107111
apiVersion: api_version,
108112
swaggerVersion: "1.1",
109113
basePath: parse_base_path(base_path, request),
110114
resourcePath: "",
111115
apis: routes_array
112116
}
117+
api_description[:models] = parse_entity_models(models) unless models.empty?
118+
api_description
113119
end
114120
end
115121

@@ -172,6 +178,19 @@ def parse_path(path, version)
172178
version ? parsed_path.gsub('{version}', version) : parsed_path
173179
end
174180

181+
def parse_entity_models(models)
182+
result = {}
183+
models.each do |model|
184+
name = model.to_s.split('::')[-1]
185+
result[name] = {
186+
id: name,
187+
name: name,
188+
properties: model.documentation
189+
}
190+
end
191+
result
192+
end
193+
175194
def parse_http_codes codes
176195
codes ||= {}
177196
codes.collect do |k, v|

spec/api_models_spec.rb

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
require 'spec_helper'
2+
3+
describe "API Models" do
4+
5+
before :all do
6+
module Entities
7+
class Something < Grape::Entity
8+
expose :text, :documentation => { :type => "string", :desc => "Content of something." }
9+
end
10+
end
11+
12+
class ModelsApi < Grape::API
13+
format :json
14+
desc 'This gets something.', {
15+
entity: Entities::Something
16+
}
17+
get '/something' do
18+
something = OpenStruct.new text: 'something'
19+
present something, with: Entities::Something
20+
end
21+
add_swagger_documentation
22+
end
23+
end
24+
25+
def app; ModelsApi; end
26+
27+
it "should document specified models" do
28+
get '/swagger_doc'
29+
JSON.parse(last_response.body).should == {
30+
"apiVersion" => "0.1",
31+
"swaggerVersion" => "1.1",
32+
"basePath" => "http://example.org",
33+
"operations" => [],
34+
"apis" => [
35+
{ "path" => "/swagger_doc/something.{format}" },
36+
{ "path" => "/swagger_doc/swagger_doc.{format}" }
37+
]
38+
}
39+
end
40+
41+
it "should include response_class when specified" do
42+
get '/swagger_doc/something.json'
43+
JSON.parse(last_response.body).should == {
44+
"apiVersion" => "0.1",
45+
"swaggerVersion" => "1.1",
46+
"basePath" => "http://example.org",
47+
"resourcePath" => "",
48+
"apis" => [
49+
{ "path" => "/something.{format}",
50+
"operations" => [
51+
{ "notes" => nil,
52+
"responseClass" => "Something",
53+
"summary" => "This gets something.",
54+
"nickname" => "GET-something---format-",
55+
"httpMethod" => "GET",
56+
"parameters" => []
57+
}
58+
]
59+
}
60+
],
61+
"models" => {
62+
"Something" => {
63+
"id" => "Something",
64+
"name" => "Something",
65+
"properties" => {
66+
"text" => {
67+
"type" => "string",
68+
"desc" => "Content of something."
69+
}
70+
}
71+
}
72+
}
73+
}
74+
end
75+
76+
end

spec/spec_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
require 'grape'
66
require 'grape-swagger'
7+
require 'grape-entity'
78

89
require 'rubygems'
910
require 'bundler'

0 commit comments

Comments
 (0)