Skip to content

Commit 229fe27

Browse files
authored
Merge pull request zipmark#347 from djezzzl/add-swagger-support
Add OpenAPI Specification support (Version 2.0)
2 parents 560c3bd + b65559c commit 229fe27

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2371
-27
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ example/public/docs
88
*.gem
99
*.swp
1010
/html/
11+
/.idea

README.md

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,16 @@ RspecApiDocumentation.configure do |config|
8080
# Set the application that Rack::Test uses
8181
config.app = Rails.application
8282

83+
# Used to provide a configuration for the specification (supported only by 'open_api' format for now)
84+
config.configurations_dir = Rails.root.join("doc", "configurations", "api")
85+
8386
# Output folder
8487
config.docs_dir = Rails.root.join("doc", "api")
8588

8689
# An array of output format(s).
8790
# Possible values are :json, :html, :combined_text, :combined_json,
8891
# :json_iodocs, :textile, :markdown, :append_json, :slate,
89-
# :api_blueprint
92+
# :api_blueprint, :open_api
9093
config.format = [:html]
9194

9295
# Location of templates
@@ -172,6 +175,7 @@ end
172175
* **markdown**: Generates an index file and example files in Markdown.
173176
* **api_blueprint**: Generates an index file and example files in [APIBlueprint](https://apiblueprint.org).
174177
* **append_json**: Lets you selectively run specs without destroying current documentation. See section below.
178+
* **open_api**: Generates [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md) (OAS) (Current supported version is 2.0). Can be used for [Swagger-UI](https://swagger.io/tools/swagger-ui/)
175179

176180
### append_json
177181

@@ -228,6 +232,173 @@ This [format](https://apiblueprint.org) (APIB) has additional functions:
228232

229233
* `attribute`: APIB has attributes besides parameters. Use attributes exactly
230234
like you'd use `parameter` (see documentation below).
235+
236+
### open_api
237+
238+
This [format](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md) (OAS) has additional functions:
239+
240+
* `authentication(type, value, opts = {})` ([Security schema object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-scheme-object))
241+
242+
The values will be passed through header of the request. Option `name` has to be provided for `apiKey`.
243+
244+
* `authentication :basic, 'Basic Key'`
245+
* `authentication :apiKey, 'Api Key', name: 'API_AUTH', description: 'Some description'`
246+
247+
You could pass `Symbol` as value. In this case you need to define a `let` with the same name.
248+
249+
```
250+
authentication :apiKey, :api_key
251+
let(:api_key) { some_value }
252+
```
253+
254+
* `route_summary(text)` and `route_description(text)`. ([Operation object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#operation-object))
255+
256+
These two simplest methods accept `String`.
257+
It will be used for route's `summary` and `description`.
258+
259+
* Several new options on `parameter` helper.
260+
261+
- `with_example: true`. This option will adjust your description of the parameter with the passed value.
262+
- `default: <value>`. Will provide a default value for the parameter.
263+
- `minimum: <integer>`. Will setup upper limit for your parameter.
264+
- `maximum: <integer>`. Will setup lower limit for your parameter.
265+
- `enum: [<value>, <value>, ..]`. Will provide a pre-defined list of possible values for your parameter.
266+
- `type: [:file, :array, :object, :boolean, :integer, :number, :string]`. Will set a type for the parameter. Most of the type you don't need to provide this option manually. We extract types from values automatically.
267+
268+
269+
You also can provide a configuration file in YAML or JSON format with some manual configs.
270+
The file should be placed in `configurations_dir` folder with the name `open_api.yml` or `open_api.json`.
271+
In this file you able to manually **hide** some endpoints/resources you want to hide from generated API specification but still want to test.
272+
It's also possible to pass almost everything to the specification builder manually.
273+
274+
#### Example of configuration file
275+
276+
```yaml
277+
swagger: '2.0'
278+
info:
279+
title: OpenAPI App
280+
description: This is a sample server.
281+
termsOfService: 'http://open-api.io/terms/'
282+
contact:
283+
name: API Support
284+
url: 'http://www.open-api.io/support'
285+
286+
license:
287+
name: Apache 2.0
288+
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
289+
version: 1.0.0
290+
host: 'localhost:3000'
291+
schemes:
292+
- http
293+
- https
294+
consumes:
295+
- application/json
296+
- application/xml
297+
produces:
298+
- application/json
299+
- application/xml
300+
paths:
301+
/orders:
302+
hide: true
303+
/instructions:
304+
hide: false
305+
get:
306+
description: This description came from configuration file
307+
hide: true
308+
```
309+
310+
#### Example of spec file
311+
312+
```ruby
313+
resource 'Orders' do
314+
explanation "Orders resource"
315+
316+
authentication :apiKey, :api_key, description: 'Private key for API access', name: 'HEADER_KEY'
317+
header "Content-Type", "application/json"
318+
319+
let(:api_key) { generate_api_key }
320+
321+
get '/orders' do
322+
route_summary "This URL allows users to interact with all orders."
323+
route_description "Long description."
324+
325+
# This is manual way to describe complex parameters
326+
parameter :one_level_array, type: :array, items: {type: :string, enum: ['string1', 'string2']}, default: ['string1']
327+
parameter :two_level_array, type: :array, items: {type: :array, items: {type: :string}}
328+
329+
let(:one_level_array) { ['string1', 'string2'] }
330+
let(:two_level_array) { [['123', '234'], ['111']] }
331+
332+
# This is automatic way
333+
# It's possible because we extract parameters definitions from the values
334+
parameter :one_level_arr, with_example: true
335+
parameter :two_level_arr, with_example: true
336+
337+
let(:one_level_arr) { ['value1', 'value2'] }
338+
let(:two_level_arr) { [[5.1, 3.0], [1.0, 4.5]] }
339+
340+
context '200' do
341+
example_request 'Getting a list of orders' do
342+
expect(status).to eq(200)
343+
expect(response_body).to eq(<response>)
344+
end
345+
end
346+
end
347+
348+
put '/orders/:id' do
349+
route_summary "This is used to update orders."
350+
351+
with_options scope: :data, with_example: true do
352+
parameter :name, 'The order name', required: true
353+
parameter :amount
354+
parameter :description, 'The order description'
355+
end
356+
357+
context "200" do
358+
let(:id) { 1 }
359+
360+
example 'Update an order' do
361+
request = {
362+
data: {
363+
name: 'order',
364+
amount: 1,
365+
description: 'fast order'
366+
}
367+
}
368+
369+
# It's also possible to extract types of parameters when you pass data through `do_request` method.
370+
do_request(request)
371+
372+
expected_response = {
373+
data: {
374+
name: 'order',
375+
amount: 1,
376+
description: 'fast order'
377+
}
378+
}
379+
expect(status).to eq(200)
380+
expect(response_body).to eq(<response>)
381+
end
382+
end
383+
384+
context "400" do
385+
let(:id) { "a" }
386+
387+
example_request 'Invalid request' do
388+
expect(status).to eq(400)
389+
end
390+
end
391+
392+
context "404" do
393+
let(:id) { 0 }
394+
395+
example_request 'Order is not found' do
396+
expect(status).to eq(404)
397+
end
398+
end
399+
end
400+
end
401+
```
231402

232403
## Filtering and Exclusion
233404

example/Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ source 'https://rubygems.org'
22

33
ruby '2.3.3'
44

5+
gem 'rack-cors', :require => 'rack/cors'
56
gem 'rails', '4.2.5.1'
67
gem 'sqlite3'
78
gem 'spring', group: :development
89
gem 'raddocs', :github => "smartlogic/raddocs"
910

1011
group :test, :development do
12+
gem 'byebug'
13+
gem 'awesome_print'
1114
gem 'rspec-rails'
1215
gem 'rspec_api_documentation', :path => "../"
1316
end

example/Gemfile.lock

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@ GIT
88
sinatra (~> 1.3, >= 1.3.0)
99

1010
PATH
11-
remote: ../
11+
remote: ..
1212
specs:
13-
rspec_api_documentation (4.7.0)
13+
rspec_api_documentation (5.1.0)
1414
activesupport (>= 3.0.0)
15-
json (~> 1.4, >= 1.4.6)
16-
mustache (~> 0.99, >= 0.99.4)
17-
rspec (>= 3.0.0)
15+
mustache (~> 1.0, >= 0.99.4)
16+
rspec (~> 3.0)
1817

1918
GEM
2019
remote: https://rubygems.org/
@@ -55,7 +54,9 @@ GEM
5554
thread_safe (~> 0.3, >= 0.3.4)
5655
tzinfo (~> 1.1)
5756
arel (6.0.3)
57+
awesome_print (1.7.0)
5858
builder (3.2.2)
59+
byebug (9.0.6)
5960
concurrent-ruby (1.0.0)
6061
diff-lcs (1.2.5)
6162
erubis (2.7.0)
@@ -72,10 +73,11 @@ GEM
7273
mime-types (2.99)
7374
mini_portile2 (2.0.0)
7475
minitest (5.8.4)
75-
mustache (0.99.8)
76+
mustache (1.0.5)
7677
nokogiri (1.6.7.2)
7778
mini_portile2 (~> 2.0.0.rc2)
7879
rack (1.6.4)
80+
rack-cors (0.4.1)
7981
rack-protection (1.5.3)
8082
rack
8183
rack-test (0.6.3)
@@ -148,12 +150,18 @@ PLATFORMS
148150
ruby
149151

150152
DEPENDENCIES
153+
awesome_print
154+
byebug
155+
rack-cors
151156
raddocs!
152157
rails (= 4.2.5.1)
153158
rspec-rails
154159
rspec_api_documentation!
155160
spring
156161
sqlite3
157162

163+
RUBY VERSION
164+
ruby 2.3.3p222
165+
158166
BUNDLED WITH
159-
1.11.2
167+
1.16.2
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
class ApplicationController < ActionController::Base
22
# Prevent CSRF attacks by raising an exception.
33
# For APIs, you may want to use :null_session instead.
4-
protect_from_forgery with: :exception
4+
# protect_from_forgery with: :exception
5+
protect_from_forgery with: :null_session
56
end

example/app/controllers/orders_controller.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
class OrdersController < ApplicationController
2+
before_action only: :index do
3+
head :unauthorized unless request.headers['HTTP_AUTH_TOKEN'] =~ /\AAPI_TOKEN$/
4+
end
5+
26
def index
37
render :json => Order.all
48
end
59

610
def show
7-
render :json => Order.find(params[:id])
11+
order = Order.find_by(id: params[:id])
12+
if order
13+
render json: order
14+
else
15+
head :not_found
16+
end
817
end
918

1019
def create

example/app/controllers/uploads_controller.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
class UploadsController < ApplicationController
2+
http_basic_authenticate_with name: 'user', password: 'password'
3+
24
def create
35
head 201
46
end

example/config/application.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515

1616
module Example
1717
class Application < Rails::Application
18+
19+
config.middleware.insert_before 0, 'Rack::Cors' do
20+
allow do
21+
origins '*'
22+
resource '*', :headers => :any, :methods => [:get, :post, :options, :put, :patch, :delete, :head]
23+
end
24+
end
25+
1826
# Settings in config/environments/* take precedence over those specified here.
1927
# Application configuration should go into files in config/initializers
2028
# -- all .rb files in that directory are automatically loaded.

example/config/open_api.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
swagger: '2.0'
2+
info:
3+
title: OpenAPI App
4+
description: This is a sample server Petstore server.
5+
termsOfService: 'http://open-api.io/terms/'
6+
contact:
7+
name: API Support
8+
url: 'http://www.open-api.io/support'
9+
10+
license:
11+
name: Apache 2.0
12+
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
13+
version: 1.0.1
14+
host: 'localhost:3000'
15+
schemes:
16+
- http
17+
- https
18+
consumes:
19+
- application/json
20+
- application/xml
21+
produces:
22+
- application/json
23+
- application/xml

example/db/schema.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
ActiveRecord::Schema.define(version: 20140616151047) do
1515

16-
create_table "orders", force: true do |t|
16+
create_table "orders", force: :cascade do |t|
1717
t.string "name"
1818
t.boolean "paid"
1919
t.string "email"

0 commit comments

Comments
 (0)