mirror of
https://github.com/ditkrg/rswag.git
synced 2026-01-22 22:06:43 +00:00
Merge branch 'master' into add-formData-support
This commit is contained in:
commit
44840ab836
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
||||
**/*/*.gem
|
||||
**/*/*.sqlite3
|
||||
**/*/public/assets
|
||||
*.swp
|
||||
|
||||
1
.ruby-version
Normal file
1
.ruby-version
Normal file
@ -0,0 +1 @@
|
||||
2.3.0
|
||||
@ -5,6 +5,7 @@ env:
|
||||
- "RAILS_VERSION=3.2.22"
|
||||
- "RAILS_VERSION=4.2.0"
|
||||
- "RAILS_VERSION=5.0.0"
|
||||
- "RAILS_VERSION=5.1.1"
|
||||
cache: bundler
|
||||
install: bundle update
|
||||
before_script:
|
||||
|
||||
14
Gemfile
14
Gemfile
@ -2,7 +2,7 @@ source "https://rubygems.org"
|
||||
|
||||
# Allow the rails version to come from an ENV setting so Travis can test multiple versions.
|
||||
# See http://www.schneems.com/post/50991826838/testing-against-multiple-rails-versions/
|
||||
rails_version = ENV['RAILS_VERSION'] || '3.2.22'
|
||||
rails_version = ENV['RAILS_VERSION'] || '5.1.2'
|
||||
|
||||
gem 'rails', "#{rails_version}"
|
||||
|
||||
@ -15,6 +15,7 @@ end
|
||||
|
||||
gem 'sqlite3'
|
||||
|
||||
gem 'rswag-specs', path: './rswag-specs'
|
||||
gem 'rswag-api', path: './rswag-api'
|
||||
gem 'rswag-ui', path: './rswag-ui'
|
||||
|
||||
@ -27,10 +28,9 @@ group :test do
|
||||
gem 'generator_spec'
|
||||
gem 'capybara'
|
||||
gem 'capybara-webkit'
|
||||
gem 'rswag-specs', path: './rswag-specs'
|
||||
end
|
||||
|
||||
group :assets do
|
||||
gem 'uglifier'
|
||||
gem 'therubyracer'
|
||||
end
|
||||
#
|
||||
#group :assets do
|
||||
# gem 'uglifier'
|
||||
# gem 'therubyracer'
|
||||
#end
|
||||
|
||||
267
Gemfile.lock
267
Gemfile.lock
@ -1,158 +1,170 @@
|
||||
PATH
|
||||
remote: ./rswag-api
|
||||
remote: rswag-api
|
||||
specs:
|
||||
rswag-api (1.2.0)
|
||||
rails (>= 3.1, < 5.1)
|
||||
rswag-api (1.3.0)
|
||||
railties (>= 3.1)
|
||||
|
||||
PATH
|
||||
remote: ./rswag-specs
|
||||
remote: rswag-specs
|
||||
specs:
|
||||
rswag-specs (1.2.0)
|
||||
json (~> 1.8)
|
||||
rswag-specs (1.3.0)
|
||||
activesupport (>= 3.1)
|
||||
json-schema (~> 2.2)
|
||||
rails (>= 3.1, < 5.1)
|
||||
rspec-rails (>= 2.14, < 4)
|
||||
railties (>= 3.1)
|
||||
|
||||
PATH
|
||||
remote: ./rswag-ui
|
||||
remote: rswag-ui
|
||||
specs:
|
||||
rswag-ui (1.2.0)
|
||||
rails (>= 3.1, < 5.1)
|
||||
rswag-ui (1.3.0)
|
||||
actionpack (>= 3.1)
|
||||
railties (>= 3.1)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actionmailer (3.2.22)
|
||||
actionpack (= 3.2.22)
|
||||
mail (~> 2.5.4)
|
||||
actionpack (3.2.22)
|
||||
activemodel (= 3.2.22)
|
||||
activesupport (= 3.2.22)
|
||||
builder (~> 3.0.0)
|
||||
erubis (~> 2.7.0)
|
||||
journey (~> 1.0.4)
|
||||
rack (~> 1.4.5)
|
||||
rack-cache (~> 1.2)
|
||||
rack-test (~> 0.6.1)
|
||||
sprockets (~> 2.2.1)
|
||||
activemodel (3.2.22)
|
||||
activesupport (= 3.2.22)
|
||||
builder (~> 3.0.0)
|
||||
activerecord (3.2.22)
|
||||
activemodel (= 3.2.22)
|
||||
activesupport (= 3.2.22)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activeresource (3.2.22)
|
||||
activemodel (= 3.2.22)
|
||||
activesupport (= 3.2.22)
|
||||
activesupport (3.2.22)
|
||||
i18n (~> 0.6, >= 0.6.4)
|
||||
multi_json (~> 1.0)
|
||||
addressable (2.4.0)
|
||||
arel (3.0.3)
|
||||
builder (3.0.4)
|
||||
capybara (2.10.1)
|
||||
actioncable (5.1.2)
|
||||
actionpack (= 5.1.2)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (~> 0.6.1)
|
||||
actionmailer (5.1.2)
|
||||
actionpack (= 5.1.2)
|
||||
actionview (= 5.1.2)
|
||||
activejob (= 5.1.2)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (5.1.2)
|
||||
actionview (= 5.1.2)
|
||||
activesupport (= 5.1.2)
|
||||
rack (~> 2.0)
|
||||
rack-test (~> 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
actionview (5.1.2)
|
||||
activesupport (= 5.1.2)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
||||
activejob (5.1.2)
|
||||
activesupport (= 5.1.2)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (5.1.2)
|
||||
activesupport (= 5.1.2)
|
||||
activerecord (5.1.2)
|
||||
activemodel (= 5.1.2)
|
||||
activesupport (= 5.1.2)
|
||||
arel (~> 8.0)
|
||||
activesupport (5.1.2)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (~> 0.7)
|
||||
minitest (~> 5.1)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.5.1)
|
||||
public_suffix (~> 2.0, >= 2.0.2)
|
||||
arel (8.0.0)
|
||||
builder (3.2.3)
|
||||
capybara (2.13.0)
|
||||
addressable
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
xpath (~> 2.0)
|
||||
capybara-webkit (1.1.0)
|
||||
capybara (~> 2.0, >= 2.0.2)
|
||||
capybara-webkit (1.14.0)
|
||||
capybara (>= 2.3.0, < 2.14.0)
|
||||
json
|
||||
diff-lcs (1.2.5)
|
||||
erubis (2.7.0)
|
||||
execjs (2.7.0)
|
||||
generator_spec (0.9.3)
|
||||
concurrent-ruby (1.0.5)
|
||||
diff-lcs (1.3)
|
||||
erubi (1.6.1)
|
||||
generator_spec (0.9.4)
|
||||
activesupport (>= 3.0.0)
|
||||
railties (>= 3.0.0)
|
||||
hike (1.2.3)
|
||||
i18n (0.7.0)
|
||||
journey (1.0.4)
|
||||
json (1.8.3)
|
||||
json-schema (2.7.0)
|
||||
globalid (0.4.0)
|
||||
activesupport (>= 4.2.0)
|
||||
i18n (0.8.4)
|
||||
json (2.1.0)
|
||||
json-schema (2.8.0)
|
||||
addressable (>= 2.4)
|
||||
libv8 (3.16.14.15)
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mime-types (1.25.1)
|
||||
mini_portile2 (2.1.0)
|
||||
multi_json (1.12.1)
|
||||
nokogiri (1.6.8.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
polyglot (0.3.5)
|
||||
power_assert (0.3.1)
|
||||
rack (1.4.7)
|
||||
rack-cache (1.6.1)
|
||||
rack (>= 0.4)
|
||||
rack-ssl (1.3.4)
|
||||
rack
|
||||
loofah (2.0.3)
|
||||
nokogiri (>= 1.5.9)
|
||||
mail (2.6.6)
|
||||
mime-types (>= 1.16, < 4)
|
||||
method_source (0.8.2)
|
||||
mime-types (3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2016.0521)
|
||||
mini_portile2 (2.2.0)
|
||||
minitest (5.10.2)
|
||||
nio4r (2.1.0)
|
||||
nokogiri (1.8.0)
|
||||
mini_portile2 (~> 2.2.0)
|
||||
power_assert (1.0.2)
|
||||
public_suffix (2.0.5)
|
||||
rack (2.0.3)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (3.2.22)
|
||||
actionmailer (= 3.2.22)
|
||||
actionpack (= 3.2.22)
|
||||
activerecord (= 3.2.22)
|
||||
activeresource (= 3.2.22)
|
||||
activesupport (= 3.2.22)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.2.22)
|
||||
railties (3.2.22)
|
||||
actionpack (= 3.2.22)
|
||||
activesupport (= 3.2.22)
|
||||
rack-ssl (~> 1.3.2)
|
||||
rails (5.1.2)
|
||||
actioncable (= 5.1.2)
|
||||
actionmailer (= 5.1.2)
|
||||
actionpack (= 5.1.2)
|
||||
actionview (= 5.1.2)
|
||||
activejob (= 5.1.2)
|
||||
activemodel (= 5.1.2)
|
||||
activerecord (= 5.1.2)
|
||||
activesupport (= 5.1.2)
|
||||
bundler (>= 1.3.0, < 2.0)
|
||||
railties (= 5.1.2)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
loofah (~> 2.0)
|
||||
railties (5.1.2)
|
||||
actionpack (= 5.1.2)
|
||||
activesupport (= 5.1.2)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rake (11.3.0)
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
ref (2.0.0)
|
||||
rspec-core (3.5.4)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-expectations (3.5.0)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rake (12.0.0)
|
||||
responders (2.4.0)
|
||||
actionpack (>= 4.2.0, < 5.3)
|
||||
railties (>= 4.2.0, < 5.3)
|
||||
rspec-core (3.6.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-expectations (3.6.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-mocks (3.5.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-mocks (3.6.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-rails (3.5.2)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-rails (3.6.0)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec-core (~> 3.5.0)
|
||||
rspec-expectations (~> 3.5.0)
|
||||
rspec-mocks (~> 3.5.0)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-support (3.5.0)
|
||||
sprockets (2.2.3)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sqlite3 (1.3.12)
|
||||
strong_parameters (0.2.3)
|
||||
actionpack (~> 3.0)
|
||||
activemodel (~> 3.0)
|
||||
activesupport (~> 3.0)
|
||||
railties (~> 3.0)
|
||||
test-unit (3.2.1)
|
||||
rspec-core (~> 3.6.0)
|
||||
rspec-expectations (~> 3.6.0)
|
||||
rspec-mocks (~> 3.6.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-support (3.6.0)
|
||||
sprockets (3.7.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.2.0)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
sqlite3 (1.3.13)
|
||||
test-unit (3.2.5)
|
||||
power_assert
|
||||
therubyracer (0.12.2)
|
||||
libv8 (~> 3.16.14.0)
|
||||
ref
|
||||
thor (0.19.1)
|
||||
tilt (1.4.1)
|
||||
treetop (1.4.15)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.51)
|
||||
uglifier (3.0.2)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
xpath (2.0.0)
|
||||
thor (0.19.4)
|
||||
thread_safe (0.3.6)
|
||||
tzinfo (1.2.3)
|
||||
thread_safe (~> 0.1)
|
||||
websocket-driver (0.6.5)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.2)
|
||||
xpath (2.1.0)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
PLATFORMS
|
||||
@ -162,13 +174,14 @@ DEPENDENCIES
|
||||
capybara
|
||||
capybara-webkit
|
||||
generator_spec
|
||||
rails (= 3.2.22)
|
||||
rails (= 5.1.2)
|
||||
responders
|
||||
rspec-rails
|
||||
rswag-api!
|
||||
rswag-specs!
|
||||
rswag-ui!
|
||||
sqlite3
|
||||
strong_parameters
|
||||
test-unit
|
||||
therubyracer
|
||||
uglifier
|
||||
|
||||
BUNDLED WITH
|
||||
1.14.6
|
||||
|
||||
79
README.md
79
README.md
@ -130,6 +130,31 @@ response '201', 'blog created' do
|
||||
end
|
||||
```
|
||||
|
||||
### Null Values ###
|
||||
|
||||
This library is currently using JSON::Draft4 for validation of response models. It does not support null as a value. So you can add the property 'x-nullable' to a definition to allow null/nil values to pass.
|
||||
```ruby
|
||||
describe 'Blogs API' do
|
||||
path '/blogs' do
|
||||
post 'Creates a blog' do
|
||||
...
|
||||
|
||||
response '200', 'blog found' do
|
||||
schema type: :object,
|
||||
properties: {
|
||||
id: { type: :integer },
|
||||
title: { type: :string },
|
||||
content: { type: :string, 'x-nullable': true }
|
||||
}
|
||||
....
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
*Note:* the OAI v3 may be released soon(ish?) and include a nullable property. This may have an effect on the need/use of custom extension to the draft. Do not use this property if you don't understand the implications.
|
||||
<https://github.com/OAI/OpenAPI-Specification/issues/229#issuecomment-280376087>
|
||||
|
||||
### Global Metadata ###
|
||||
|
||||
In addition to paths, operations and responses, Swagger also supports global API metadata. When you install rswag, a file called _swagger_helper.rb_ is added to your spec folder. This is where you define one or more Swagger documents and provide global metadata. Again, the format is based on Swagger so most of the global fields supported by the top level ["Swagger" object](http://swagger.io/specification/#swaggerObject) can be provided with each document definition. As an example, you could define a Swagger document for each version of your API and in each case specify a title, version string and URL basePath:
|
||||
@ -175,6 +200,58 @@ describe 'Blogs API', swagger_doc: 'v2/swagger.json' do
|
||||
end
|
||||
```
|
||||
|
||||
### Specifying/Testing API Security ###
|
||||
|
||||
Swagger allows for the specification of different security schemes and their applicability to operations in an API. To leverage this in rswag, you define the schemes globally in _swagger_helper.rb_ and then use the "security" attribute at the operation level to specify which schemes, if any, are applicable to that operation. Swagger supports :basic, :apiKey and :oauth2 scheme types. See [the spec](http://swagger.io/specification/#security-definitions-object-109) for more info.
|
||||
|
||||
```ruby
|
||||
# spec/swagger_helper.rb
|
||||
RSpec.configure do |config|
|
||||
config.swagger_root = Rails.root.to_s + '/swagger'
|
||||
|
||||
config.swagger_docs = {
|
||||
'v1/swagger.json' => {
|
||||
...
|
||||
securityDefinitions: {
|
||||
basic: {
|
||||
type: :basic
|
||||
},
|
||||
apiKey: {
|
||||
type: :apiKey,
|
||||
name: 'api_key',
|
||||
in: :query
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# spec/integration/blogs_spec.rb
|
||||
describe 'Blogs API' do
|
||||
|
||||
path '/blogs' do
|
||||
|
||||
post 'Creates a blog' do
|
||||
tags 'Blogs'
|
||||
security [ basic: [] ]
|
||||
...
|
||||
|
||||
response '201', 'blog created' do
|
||||
let(:Authorization) { "Basic #{::Base64.strict_encode64('jsmith:jspass')}" }
|
||||
run_test!
|
||||
end
|
||||
|
||||
response '401', 'authentication failed' do
|
||||
let(:Authorization) { "Basic #{::Base64.strict_encode64('bogus:bogus')}" }
|
||||
run_test!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
__NOTE:__ Depending on the scheme types, you'll be required to assign a corresponding parameter value with each example. For example, :basic auth is required above and so the :Authorization (header) parameter must be set accordingly
|
||||
|
||||
## Configuration & Customization ##
|
||||
|
||||
The steps described above will get you up and running with minimal setup. However, rswag offers a lot of flexibility to customize as you see fit. Before exploring the various options, you'll need to be aware of it's different components. The following table lists each of them and the files that get added/updated as part of a standard install.
|
||||
@ -382,7 +459,7 @@ end
|
||||
|
||||
### Customizing the swagger-ui ###
|
||||
|
||||
The swagger-ui provides several options for customizing it's behavior, all of which are documented here https://github.com/swagger-api/swagger-ui#swaggerui. If you need to tweak these or customize the overall look and feel of your swagger-ui, then you'll need to provide your own version of index.html. You can do this with the following generator.
|
||||
The swagger-ui provides several options for customizing it's behavior, all of which are documented here https://github.com/swagger-api/swagger-ui/tree/2.x#swaggerui. If you need to tweak these or customize the overall look and feel of your swagger-ui, then you'll need to provide your own version of index.html. You can do this with the following generator.
|
||||
|
||||
```ruby
|
||||
rails g rswag:ui:custom
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module Rswag
|
||||
module Api
|
||||
VERSION = '1.2.0'
|
||||
VERSION = '1.3.0'
|
||||
end
|
||||
end
|
||||
|
||||
@ -14,7 +14,7 @@ Gem::Specification.new do |s|
|
||||
s.description = "Open up your API to the phenomenal Swagger ecosystem by exposing Swagger files, that describe your service, as JSON endpoints"
|
||||
s.license = "MIT"
|
||||
|
||||
s.files = Dir["{lib}/**/*"] + ["MIT-LICENSE", "Rakefile" ]
|
||||
s.files = Dir["{lib}/**/*"] + ["MIT-LICENSE", "Rakefile"]
|
||||
|
||||
s.add_dependency "rails", ">= 3.1", "< 5.1"
|
||||
s.add_dependency 'railties', '>= 3.1'
|
||||
end
|
||||
|
||||
@ -14,7 +14,7 @@ module Rswag
|
||||
api_metadata[:operation][:verb],
|
||||
factory.build_fullpath(self),
|
||||
factory.build_body(self),
|
||||
factory.build_headers(self)
|
||||
rackify_headers(factory.build_headers(self)) # Rails test infrastructure requires Rack headers
|
||||
)
|
||||
else
|
||||
send(
|
||||
@ -36,6 +36,22 @@ module Rswag
|
||||
|
||||
private
|
||||
|
||||
def rackify_headers(headers)
|
||||
name_value_pairs = headers.map do |name, value|
|
||||
[
|
||||
case name
|
||||
when 'Accept' then 'HTTP_ACCEPT'
|
||||
when 'Content-Type' then 'CONTENT_TYPE'
|
||||
when 'Authorization' then 'HTTP_AUTHORIZATION'
|
||||
else name
|
||||
end,
|
||||
value
|
||||
]
|
||||
end
|
||||
|
||||
Hash[ name_value_pairs ]
|
||||
end
|
||||
|
||||
def rswag_config
|
||||
::Rswag::Specs.config
|
||||
end
|
||||
|
||||
@ -2,18 +2,18 @@ require 'json-schema'
|
||||
|
||||
module Rswag
|
||||
module Specs
|
||||
class ExtendedSchema < JSON::Schema::Validator
|
||||
|
||||
class ExtendedSchema < JSON::Schema::Draft4
|
||||
|
||||
def initialize
|
||||
super
|
||||
extend_schema_definition("http://json-schema.org/draft-04/schema#")
|
||||
@attributes['type'] = ExtendedTypeAttribute
|
||||
@uri = URI.parse('http://tempuri.org/rswag/specs/extended_schema')
|
||||
@names = ['http://tempuri.org/rswag/specs/extended_schema']
|
||||
end
|
||||
end
|
||||
|
||||
class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute
|
||||
|
||||
|
||||
def self.validate(current_schema, data, fragments, processor, validator, options={})
|
||||
return if data.nil? && current_schema.schema['x-nullable'] == true
|
||||
super
|
||||
|
||||
@ -33,13 +33,20 @@ module Rswag
|
||||
end
|
||||
|
||||
def build_headers(example)
|
||||
headers = Hash[ parameters_in(:header).map { |p| [ p[:name], example.send(p[:name]).to_s ] } ]
|
||||
headers.tap do |h|
|
||||
produces = @api_metadata[:operation][:produces] || @global_metadata[:produces]
|
||||
consumes = @api_metadata[:operation][:consumes] || @global_metadata[:consumes]
|
||||
h['ACCEPT'] = produces.join(';') unless produces.nil?
|
||||
h['CONTENT_TYPE'] = consumes.join(';') unless consumes.nil?
|
||||
name_value_pairs = parameters_in(:header).map do |param|
|
||||
[
|
||||
param[:name],
|
||||
example.send(param[:name]).to_s
|
||||
]
|
||||
end
|
||||
|
||||
# Add MIME type headers based on produces/consumes metadata
|
||||
produces = @api_metadata[:operation][:produces] || @global_metadata[:produces]
|
||||
consumes = @api_metadata[:operation][:consumes] || @global_metadata[:consumes]
|
||||
name_value_pairs << [ 'Accept', produces.join(';') ] unless produces.nil?
|
||||
name_value_pairs << [ 'Content-Type', consumes.join(';') ] unless consumes.nil?
|
||||
|
||||
Hash[ name_value_pairs ]
|
||||
end
|
||||
|
||||
private
|
||||
@ -53,42 +60,48 @@ module Rswag
|
||||
|
||||
applicable_params
|
||||
.map { |p| p['$ref'] ? resolve_parameter(p['$ref']) : p } # resolve any references
|
||||
.concat(resolve_api_key_parameters)
|
||||
.concat(security_parameters)
|
||||
.select { |p| p[:in] == location }
|
||||
end
|
||||
|
||||
def resolve_parameter(ref)
|
||||
defined_params = @global_metadata[:parameters]
|
||||
defined_params = @global_metadata[:parameters]
|
||||
key = ref.sub('#/parameters/', '')
|
||||
raise "Referenced parameter '#{ref}' must be defined" unless defined_params && defined_params[key]
|
||||
defined_params[key]
|
||||
end
|
||||
|
||||
def resolve_api_key_parameters
|
||||
@api_key_params ||= begin
|
||||
# First figure out the security requirement applicable to the operation
|
||||
global_requirements = (@global_metadata[:security] || [] ).map { |r| r.keys.first }
|
||||
operation_requirements = (@api_metadata[:operation][:security] || [] ).map { |r| r.keys.first }
|
||||
requirements = global_requirements | operation_requirements
|
||||
|
||||
# Then obtain the scheme definitions for those requirements
|
||||
definitions = (@global_metadata[:securityDefinitions] || {}).slice(*requirements)
|
||||
definitions.values.select { |d| d[:type] == :apiKey }
|
||||
def security_parameters
|
||||
applicable_security_schemes.map do |scheme|
|
||||
if scheme[:type] == :apiKey
|
||||
{ name: scheme[:name], type: :string, in: scheme[:in] }
|
||||
else
|
||||
{ name: 'Authorization', type: :string, in: :header } # use auth header for basic & oauth2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def applicable_security_schemes
|
||||
# First figure out the security requirement applicable to the operation
|
||||
requirements = @api_metadata[:operation][:security] || @global_metadata[:security]
|
||||
scheme_names = requirements ? requirements.map { |r| r.keys.first } : []
|
||||
|
||||
# Then obtain the scheme definitions for those requirements
|
||||
(@global_metadata[:securityDefinitions] || {}).slice(*scheme_names).values
|
||||
end
|
||||
|
||||
def build_query_string_part(param, value)
|
||||
return "#{param[:name]}=#{value.to_s}" unless param[:type].to_sym == :array
|
||||
|
||||
name = param[:name]
|
||||
case param[:collectionFormat]
|
||||
when :ssv
|
||||
when :ssv
|
||||
"#{name}=#{value.join(' ')}"
|
||||
when :tsv
|
||||
when :tsv
|
||||
"#{name}=#{value.join('\t')}"
|
||||
when :pipes
|
||||
when :pipes
|
||||
"#{name}=#{value.join('|')}"
|
||||
when :multi
|
||||
when :multi
|
||||
value.map { |v| "#{name}=#{v}" }.join('&')
|
||||
else
|
||||
"#{name}=#{value.join(',')}" # csv is default
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module Rswag
|
||||
module Specs
|
||||
VERSION = '1.2.0'
|
||||
VERSION = '1.3.0'
|
||||
end
|
||||
end
|
||||
|
||||
@ -16,8 +16,7 @@ Gem::Specification.new do |s|
|
||||
|
||||
s.files = Dir["{lib}/**/*"] + ["MIT-LICENSE", "Rakefile" ]
|
||||
|
||||
s.add_dependency "rails", ">= 3.1", "< 5.1"
|
||||
s.add_dependency 'json', '~> 1.8'
|
||||
s.add_dependency 'activesupport', '>= 3.1'
|
||||
s.add_dependency 'railties', '>= 3.1'
|
||||
s.add_dependency 'json-schema', '~> 2.2'
|
||||
s.add_dependency 'rspec-rails', '>= 2.14', '< 4'
|
||||
end
|
||||
|
||||
@ -218,6 +218,33 @@ module Rswag
|
||||
end
|
||||
end
|
||||
|
||||
context "global definition for 'basic auth'" do
|
||||
before do
|
||||
global_metadata[:securityDefinitions] = { basic_auth: { type: :basic} }
|
||||
allow(example).to receive(:'Authorization').and_return('Basic foobar')
|
||||
end
|
||||
|
||||
context 'global requirement' do
|
||||
before { global_metadata[:security] = [ { basic_auth: [] } ] }
|
||||
|
||||
it "includes a corresponding Authorization header" do
|
||||
expect(headers).to match(
|
||||
'Authorization' => 'Basic foobar'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'operation-specific requirement' do
|
||||
before { api_metadata[:operation][:security] = [ { basic_auth: [] } ] }
|
||||
|
||||
it "includes a corresponding Authorization header" do
|
||||
expect(headers).to match(
|
||||
'Authorization' => 'Basic foobar'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'consumes & produces' do
|
||||
before do
|
||||
api_metadata[:operation][:consumes] = [ 'application/json', 'application/xml' ]
|
||||
@ -226,8 +253,8 @@ module Rswag
|
||||
|
||||
it "includes corresponding 'Accept' & 'Content-Type' headers" do
|
||||
expect(headers).to match(
|
||||
'ACCEPT' => 'application/json;application/xml',
|
||||
'CONTENT_TYPE' => 'application/json;application/xml'
|
||||
'Accept' => 'application/json;application/xml',
|
||||
'Content-Type' => 'application/json;application/xml'
|
||||
)
|
||||
end
|
||||
end
|
||||
@ -242,8 +269,8 @@ module Rswag
|
||||
|
||||
it "includes corresponding 'Accept' & 'Content-Type' headers" do
|
||||
expect(headers).to match(
|
||||
'ACCEPT' => 'application/json;application/xml',
|
||||
'CONTENT_TYPE' => 'application/json;application/xml'
|
||||
'Accept' => 'application/json;application/xml',
|
||||
'Content-Type' => 'application/json;application/xml'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@ -5,7 +5,14 @@ module Rswag
|
||||
|
||||
initializer 'rswag-ui.initialize' do |app|
|
||||
if app.config.respond_to?(:assets)
|
||||
app.config.assets.precompile += [ 'swagger-ui/*' ]
|
||||
app.config.assets.precompile += [
|
||||
'swagger-ui/css/*',
|
||||
'swagger-ui/fonts/*',
|
||||
'swagger-ui/images/*',
|
||||
'swagger-ui/lang/*',
|
||||
'swagger-ui/lib/*',
|
||||
'swagger-ui/swagger-ui.min.js'
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module Rswag
|
||||
module Ui
|
||||
VERSION = '1.2.0'
|
||||
VERSION = '1.3.0'
|
||||
end
|
||||
end
|
||||
|
||||
@ -16,5 +16,6 @@ Gem::Specification.new do |s|
|
||||
|
||||
s.files = Dir["{app,config,lib,vendor}/**/*"] + ["MIT-LICENSE", "Rakefile" ]
|
||||
|
||||
s.add_dependency "rails", ">= 3.1", "< 5.1"
|
||||
s.add_dependency 'actionpack', '>=3.1'
|
||||
s.add_dependency 'railties', '>= 3.1'
|
||||
end
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
module Rswag
|
||||
VERSION = '1.2.0'
|
||||
VERSION = '1.3.0'
|
||||
end
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
class ApplicationController < ActionController::Base
|
||||
# Prevent CSRF attacks by raising an exception.
|
||||
# For APIs, you may want to use :null_session instead.
|
||||
protect_from_forgery with: :exception
|
||||
protect_from_forgery with: :null_session
|
||||
|
||||
wrap_parameters format: [ :json ]
|
||||
end
|
||||
|
||||
13
test-app/app/controllers/auth_tests_controller.rb
Normal file
13
test-app/app/controllers/auth_tests_controller.rb
Normal file
@ -0,0 +1,13 @@
|
||||
class AuthTestsController < ApplicationController
|
||||
wrap_parameters Blog
|
||||
respond_to :json
|
||||
|
||||
# POST /auth-tests/basic
|
||||
def basic
|
||||
if authenticate_with_http_basic { |u, p| u == 'jsmith' && p == 'jspass' }
|
||||
head :no_content
|
||||
else
|
||||
request_http_basic_authentication
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -5,7 +5,7 @@ class Blog < ActiveRecord::Base
|
||||
{
|
||||
id: id,
|
||||
title: title,
|
||||
content: content,
|
||||
content: nil,
|
||||
thumbnail: thumbnail
|
||||
}
|
||||
end
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
require 'rubygems'
|
||||
gemfile = File.expand_path('../../../../Gemfile', __FILE__)
|
||||
gemfile = File.expand_path('../../../Gemfile', __FILE__)
|
||||
|
||||
if File.exist?(gemfile)
|
||||
ENV['BUNDLE_GEMFILE'] = gemfile
|
||||
@ -7,4 +7,4 @@ if File.exist?(gemfile)
|
||||
Bundler.setup
|
||||
end
|
||||
|
||||
$:.unshift File.expand_path('../../../../lib', __FILE__)
|
||||
$:.unshift File.expand_path('../../../../lib', __FILE__)
|
||||
|
||||
@ -28,4 +28,6 @@ TestApp::Application.configure do
|
||||
|
||||
# Expands the lines which load the assets
|
||||
config.assets.debug = true
|
||||
|
||||
config.eager_load = false
|
||||
end
|
||||
|
||||
@ -1,67 +0,0 @@
|
||||
TestApp::Application.configure do
|
||||
# Settings specified here will take precedence over those in config/application.rb
|
||||
|
||||
# Code is not reloaded between requests
|
||||
config.cache_classes = true
|
||||
|
||||
# Full error reports are disabled and caching is turned on
|
||||
config.consider_all_requests_local = false
|
||||
config.action_controller.perform_caching = true
|
||||
|
||||
# Disable Rails's static asset server (Apache or nginx will already do this)
|
||||
config.serve_static_assets = true
|
||||
|
||||
# Compress JavaScripts and CSS
|
||||
config.assets.compress = true
|
||||
|
||||
# Don't fallback to assets pipeline if a precompiled asset is missed
|
||||
config.assets.compile = false
|
||||
|
||||
# Generate digests for assets URLs
|
||||
config.assets.digest = true
|
||||
|
||||
# Defaults to nil and saved in location specified by config.assets.prefix
|
||||
# config.assets.manifest = YOUR_PATH
|
||||
|
||||
# Specifies the header that your server uses for sending files
|
||||
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
|
||||
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
|
||||
|
||||
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
||||
# config.force_ssl = true
|
||||
|
||||
# See everything in the log (default is :info)
|
||||
# config.log_level = :debug
|
||||
|
||||
# Prepend all log lines with the following tags
|
||||
# config.log_tags = [ :subdomain, :uuid ]
|
||||
|
||||
# Use a different logger for distributed setups
|
||||
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
|
||||
|
||||
# Use a different cache store in production
|
||||
# config.cache_store = :mem_cache_store
|
||||
|
||||
# Enable serving of images, stylesheets, and JavaScripts from an asset server
|
||||
# config.action_controller.asset_host = "http://assets.example.com"
|
||||
|
||||
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
|
||||
# config.assets.precompile += %w( search.js )
|
||||
|
||||
# Disable delivery errors, bad email addresses will be ignored
|
||||
# config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
# Enable threaded mode
|
||||
# config.threadsafe!
|
||||
|
||||
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
||||
# the I18n.default_locale when a translation can not be found)
|
||||
config.i18n.fallbacks = true
|
||||
|
||||
# Send deprecation notices to registered listeners
|
||||
config.active_support.deprecation = :notify
|
||||
|
||||
# Log the query plan for queries taking more than this (works
|
||||
# with SQLite, MySQL, and PostgreSQL)
|
||||
# config.active_record.auto_explain_threshold_in_seconds = 0.5
|
||||
end
|
||||
@ -32,4 +32,6 @@ TestApp::Application.configure do
|
||||
|
||||
# Print deprecation notices to the stderr
|
||||
config.active_support.deprecation = :stderr
|
||||
|
||||
config.eager_load = false
|
||||
end
|
||||
|
||||
@ -5,3 +5,6 @@
|
||||
# Make sure the secret is at least 30 characters and all random,
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
TestApp::Application.config.secret_token = '60f36cd33756d73f362053f1d45256ae50d75440b634ae73b070a6e35a2df38692f59e28e5ecbd1f9f2e850255f6d29a468bc59ac4484c2b7f0548ddbfc1b870'
|
||||
|
||||
# See http://guides.rubyonrails.org/upgrading_ruby_on_rails.html#config-secrets-yml
|
||||
TestApp::Application.config.secret_key_base = 'f6a820cc8aa76094583cd68ef46a735e25e3278648086355f8bd24721f036959c728c06a28dcecfe695f17ae2db44dfa1424f22b81377f2a1496d4e19f6f7faa'
|
||||
|
||||
@ -2,6 +2,8 @@ TestApp::Application.routes.draw do
|
||||
resources :blogs, defaults: { :format => :json }
|
||||
put '/blogs/:id/upload', to: 'blogs#upload'
|
||||
|
||||
post 'auth-tests/basic', to: 'auth_tests#basic'
|
||||
|
||||
mount Rswag::Api::Engine => 'api-docs'
|
||||
mount Rswag::Ui::Engine => 'api-docs'
|
||||
end
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
class CreateBlogs < ActiveRecord::Migration
|
||||
migration_class = if Gem::Version.new(Rails.version) >= Gem::Version.new("5.0")
|
||||
ActiveRecord::Migration[4.2]
|
||||
else
|
||||
ActiveRecord::Migration
|
||||
end
|
||||
|
||||
class CreateBlogs < migration_class
|
||||
def change
|
||||
create_table :blogs do |t|
|
||||
t.string :title
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
# encoding: UTF-8
|
||||
# This file is auto-generated from the current state of the database. Instead
|
||||
# of editing this file, please use the migrations feature of Active Record to
|
||||
# incrementally modify your database, and then regenerate this schema definition.
|
||||
@ -9,16 +8,16 @@
|
||||
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
||||
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
||||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20160218212104) do
|
||||
ActiveRecord::Schema.define(version: 20160218212104) do
|
||||
|
||||
create_table "blogs", :force => true do |t|
|
||||
t.string "title"
|
||||
t.text "content"
|
||||
create_table "blogs", force: :cascade do |t|
|
||||
t.string "title", limit: 255
|
||||
t.text "content"
|
||||
t.string "thumbnail"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
22
test-app/spec/integration/auth_tests_spec.rb
Normal file
22
test-app/spec/integration/auth_tests_spec.rb
Normal file
@ -0,0 +1,22 @@
|
||||
require 'swagger_helper'
|
||||
|
||||
describe 'Auth Tests API', type: :request, swagger_doc: 'v1/swagger.json' do
|
||||
|
||||
path '/auth-tests/basic' do
|
||||
post 'Authenticates with basic auth' do
|
||||
tags 'Auth Test'
|
||||
operationId 'testBasicAuth'
|
||||
security [ basic_auth: [] ]
|
||||
|
||||
response '204', 'Valid credentials' do
|
||||
let(:Authorization) { "Basic #{::Base64.strict_encode64('jsmith:jspass')}" }
|
||||
run_test!
|
||||
end
|
||||
|
||||
response '401', 'Invalid credentials' do
|
||||
let(:Authorization) { "Basic #{::Base64.strict_encode64('foo:bar')}" }
|
||||
run_test!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -39,13 +39,16 @@ RSpec.configure do |config|
|
||||
properties: {
|
||||
id: { type: 'integer' },
|
||||
title: { type: 'string' },
|
||||
content: { type: 'string' },
|
||||
content: { type: 'string', 'x-nullable': true },
|
||||
thumbnail: { type: 'string'}
|
||||
},
|
||||
required: [ 'id', 'title', 'content', 'thumbnail' ]
|
||||
}
|
||||
},
|
||||
securityDefinitions: {
|
||||
basic_auth: {
|
||||
type: :basic
|
||||
},
|
||||
api_key: {
|
||||
type: :apiKey,
|
||||
name: 'api_key',
|
||||
|
||||
@ -5,6 +5,30 @@
|
||||
"version": "v1"
|
||||
},
|
||||
"paths": {
|
||||
"/auth-tests/basic": {
|
||||
"post": {
|
||||
"summary": "Authenticates with basic auth",
|
||||
"tags": [
|
||||
"Auth Test"
|
||||
],
|
||||
"operationId": "testBasicAuth",
|
||||
"security": [
|
||||
{
|
||||
"basic_auth": [
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "Valid credentials"
|
||||
},
|
||||
"401": {
|
||||
"description": "Invalid credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/blogs": {
|
||||
"post": {
|
||||
"summary": "Creates a blog",
|
||||
@ -192,7 +216,8 @@
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"x-nullable": true
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
@ -207,6 +232,9 @@
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"basic_auth": {
|
||||
"type": "basic"
|
||||
},
|
||||
"api_key": {
|
||||
"type": "apiKey",
|
||||
"name": "api_key",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user