Merge branch 'master' into add-formData-support

This commit is contained in:
Ali Qanavatian
2017-07-04 09:45:33 +04:30
committed by GitHub
32 changed files with 428 additions and 259 deletions

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@
**/*/*.gem **/*/*.gem
**/*/*.sqlite3 **/*/*.sqlite3
**/*/public/assets **/*/public/assets
*.swp

1
.ruby-version Normal file
View File

@@ -0,0 +1 @@
2.3.0

View File

@@ -5,6 +5,7 @@ env:
- "RAILS_VERSION=3.2.22" - "RAILS_VERSION=3.2.22"
- "RAILS_VERSION=4.2.0" - "RAILS_VERSION=4.2.0"
- "RAILS_VERSION=5.0.0" - "RAILS_VERSION=5.0.0"
- "RAILS_VERSION=5.1.1"
cache: bundler cache: bundler
install: bundle update install: bundle update
before_script: before_script:

14
Gemfile
View File

@@ -2,7 +2,7 @@ source "https://rubygems.org"
# Allow the rails version to come from an ENV setting so Travis can test multiple versions. # 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/ # 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}" gem 'rails', "#{rails_version}"
@@ -15,6 +15,7 @@ end
gem 'sqlite3' gem 'sqlite3'
gem 'rswag-specs', path: './rswag-specs'
gem 'rswag-api', path: './rswag-api' gem 'rswag-api', path: './rswag-api'
gem 'rswag-ui', path: './rswag-ui' gem 'rswag-ui', path: './rswag-ui'
@@ -27,10 +28,9 @@ group :test do
gem 'generator_spec' gem 'generator_spec'
gem 'capybara' gem 'capybara'
gem 'capybara-webkit' gem 'capybara-webkit'
gem 'rswag-specs', path: './rswag-specs'
end
group :assets do
gem 'uglifier'
gem 'therubyracer'
end end
#
#group :assets do
# gem 'uglifier'
# gem 'therubyracer'
#end

View File

@@ -1,158 +1,170 @@
PATH PATH
remote: ./rswag-api remote: rswag-api
specs: specs:
rswag-api (1.2.0) rswag-api (1.3.0)
rails (>= 3.1, < 5.1) railties (>= 3.1)
PATH PATH
remote: ./rswag-specs remote: rswag-specs
specs: specs:
rswag-specs (1.2.0) rswag-specs (1.3.0)
json (~> 1.8) activesupport (>= 3.1)
json-schema (~> 2.2) json-schema (~> 2.2)
rails (>= 3.1, < 5.1) railties (>= 3.1)
rspec-rails (>= 2.14, < 4)
PATH PATH
remote: ./rswag-ui remote: rswag-ui
specs: specs:
rswag-ui (1.2.0) rswag-ui (1.3.0)
rails (>= 3.1, < 5.1) actionpack (>= 3.1)
railties (>= 3.1)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actionmailer (3.2.22) actioncable (5.1.2)
actionpack (= 3.2.22) actionpack (= 5.1.2)
mail (~> 2.5.4) nio4r (~> 2.0)
actionpack (3.2.22) websocket-driver (~> 0.6.1)
activemodel (= 3.2.22) actionmailer (5.1.2)
activesupport (= 3.2.22) actionpack (= 5.1.2)
builder (~> 3.0.0) actionview (= 5.1.2)
erubis (~> 2.7.0) activejob (= 5.1.2)
journey (~> 1.0.4) mail (~> 2.5, >= 2.5.4)
rack (~> 1.4.5) rails-dom-testing (~> 2.0)
rack-cache (~> 1.2) actionpack (5.1.2)
rack-test (~> 0.6.1) actionview (= 5.1.2)
sprockets (~> 2.2.1) activesupport (= 5.1.2)
activemodel (3.2.22) rack (~> 2.0)
activesupport (= 3.2.22) rack-test (~> 0.6.3)
builder (~> 3.0.0) rails-dom-testing (~> 2.0)
activerecord (3.2.22) rails-html-sanitizer (~> 1.0, >= 1.0.2)
activemodel (= 3.2.22) actionview (5.1.2)
activesupport (= 3.2.22) activesupport (= 5.1.2)
arel (~> 3.0.2) builder (~> 3.1)
tzinfo (~> 0.3.29) erubi (~> 1.4)
activeresource (3.2.22) rails-dom-testing (~> 2.0)
activemodel (= 3.2.22) rails-html-sanitizer (~> 1.0, >= 1.0.3)
activesupport (= 3.2.22) activejob (5.1.2)
activesupport (3.2.22) activesupport (= 5.1.2)
i18n (~> 0.6, >= 0.6.4) globalid (>= 0.3.6)
multi_json (~> 1.0) activemodel (5.1.2)
addressable (2.4.0) activesupport (= 5.1.2)
arel (3.0.3) activerecord (5.1.2)
builder (3.0.4) activemodel (= 5.1.2)
capybara (2.10.1) 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 addressable
mime-types (>= 1.16) mime-types (>= 1.16)
nokogiri (>= 1.3.3) nokogiri (>= 1.3.3)
rack (>= 1.0.0) rack (>= 1.0.0)
rack-test (>= 0.5.4) rack-test (>= 0.5.4)
xpath (~> 2.0) xpath (~> 2.0)
capybara-webkit (1.1.0) capybara-webkit (1.14.0)
capybara (~> 2.0, >= 2.0.2) capybara (>= 2.3.0, < 2.14.0)
json json
diff-lcs (1.2.5) concurrent-ruby (1.0.5)
erubis (2.7.0) diff-lcs (1.3)
execjs (2.7.0) erubi (1.6.1)
generator_spec (0.9.3) generator_spec (0.9.4)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
railties (>= 3.0.0) railties (>= 3.0.0)
hike (1.2.3) globalid (0.4.0)
i18n (0.7.0) activesupport (>= 4.2.0)
journey (1.0.4) i18n (0.8.4)
json (1.8.3) json (2.1.0)
json-schema (2.7.0) json-schema (2.8.0)
addressable (>= 2.4) addressable (>= 2.4)
libv8 (3.16.14.15) loofah (2.0.3)
mail (2.5.4) nokogiri (>= 1.5.9)
mime-types (~> 1.16) mail (2.6.6)
treetop (~> 1.4.8) mime-types (>= 1.16, < 4)
mime-types (1.25.1) method_source (0.8.2)
mini_portile2 (2.1.0) mime-types (3.1)
multi_json (1.12.1) mime-types-data (~> 3.2015)
nokogiri (1.6.8.1) mime-types-data (3.2016.0521)
mini_portile2 (~> 2.1.0) mini_portile2 (2.2.0)
polyglot (0.3.5) minitest (5.10.2)
power_assert (0.3.1) nio4r (2.1.0)
rack (1.4.7) nokogiri (1.8.0)
rack-cache (1.6.1) mini_portile2 (~> 2.2.0)
rack (>= 0.4) power_assert (1.0.2)
rack-ssl (1.3.4) public_suffix (2.0.5)
rack rack (2.0.3)
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rails (3.2.22) rails (5.1.2)
actionmailer (= 3.2.22) actioncable (= 5.1.2)
actionpack (= 3.2.22) actionmailer (= 5.1.2)
activerecord (= 3.2.22) actionpack (= 5.1.2)
activeresource (= 3.2.22) actionview (= 5.1.2)
activesupport (= 3.2.22) activejob (= 5.1.2)
bundler (~> 1.0) activemodel (= 5.1.2)
railties (= 3.2.22) activerecord (= 5.1.2)
railties (3.2.22) activesupport (= 5.1.2)
actionpack (= 3.2.22) bundler (>= 1.3.0, < 2.0)
activesupport (= 3.2.22) railties (= 5.1.2)
rack-ssl (~> 1.3.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) rake (>= 0.8.7)
rdoc (~> 3.4) thor (>= 0.18.1, < 2.0)
thor (>= 0.14.6, < 2.0) rake (12.0.0)
rake (11.3.0) responders (2.4.0)
rdoc (3.12.2) actionpack (>= 4.2.0, < 5.3)
json (~> 1.4) railties (>= 4.2.0, < 5.3)
ref (2.0.0) rspec-core (3.6.0)
rspec-core (3.5.4) rspec-support (~> 3.6.0)
rspec-support (~> 3.5.0) rspec-expectations (3.6.0)
rspec-expectations (3.5.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0) rspec-support (~> 3.6.0)
rspec-mocks (3.5.0) rspec-mocks (3.6.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0) rspec-support (~> 3.6.0)
rspec-rails (3.5.2) rspec-rails (3.6.0)
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
railties (>= 3.0) railties (>= 3.0)
rspec-core (~> 3.5.0) rspec-core (~> 3.6.0)
rspec-expectations (~> 3.5.0) rspec-expectations (~> 3.6.0)
rspec-mocks (~> 3.5.0) rspec-mocks (~> 3.6.0)
rspec-support (~> 3.5.0) rspec-support (~> 3.6.0)
rspec-support (3.5.0) rspec-support (3.6.0)
sprockets (2.2.3) sprockets (3.7.1)
hike (~> 1.2) concurrent-ruby (~> 1.0)
multi_json (~> 1.0) rack (> 1, < 3)
rack (~> 1.0) sprockets-rails (3.2.0)
tilt (~> 1.1, != 1.3.0) actionpack (>= 4.0)
sqlite3 (1.3.12) activesupport (>= 4.0)
strong_parameters (0.2.3) sprockets (>= 3.0.0)
actionpack (~> 3.0) sqlite3 (1.3.13)
activemodel (~> 3.0) test-unit (3.2.5)
activesupport (~> 3.0)
railties (~> 3.0)
test-unit (3.2.1)
power_assert power_assert
therubyracer (0.12.2) thor (0.19.4)
libv8 (~> 3.16.14.0) thread_safe (0.3.6)
ref tzinfo (1.2.3)
thor (0.19.1) thread_safe (~> 0.1)
tilt (1.4.1) websocket-driver (0.6.5)
treetop (1.4.15) websocket-extensions (>= 0.1.0)
polyglot websocket-extensions (0.1.2)
polyglot (>= 0.3.1) xpath (2.1.0)
tzinfo (0.3.51)
uglifier (3.0.2)
execjs (>= 0.3.0, < 3)
xpath (2.0.0)
nokogiri (~> 1.3) nokogiri (~> 1.3)
PLATFORMS PLATFORMS
@@ -162,13 +174,14 @@ DEPENDENCIES
capybara capybara
capybara-webkit capybara-webkit
generator_spec generator_spec
rails (= 3.2.22) rails (= 5.1.2)
responders
rspec-rails rspec-rails
rswag-api! rswag-api!
rswag-specs! rswag-specs!
rswag-ui! rswag-ui!
sqlite3 sqlite3
strong_parameters
test-unit test-unit
therubyracer
uglifier BUNDLED WITH
1.14.6

View File

@@ -130,6 +130,31 @@ response '201', 'blog created' do
end 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 ### ### 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: 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 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 ## ## 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. 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 ### ### 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 ```ruby
rails g rswag:ui:custom rails g rswag:ui:custom

View File

@@ -1,5 +1,5 @@
module Rswag module Rswag
module Api module Api
VERSION = '1.2.0' VERSION = '1.3.0'
end end
end end

View File

@@ -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.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.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 end

View File

@@ -14,7 +14,7 @@ module Rswag
api_metadata[:operation][:verb], api_metadata[:operation][:verb],
factory.build_fullpath(self), factory.build_fullpath(self),
factory.build_body(self), factory.build_body(self),
factory.build_headers(self) rackify_headers(factory.build_headers(self)) # Rails test infrastructure requires Rack headers
) )
else else
send( send(
@@ -36,6 +36,22 @@ module Rswag
private 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 def rswag_config
::Rswag::Specs.config ::Rswag::Specs.config
end end

View File

@@ -2,18 +2,18 @@ require 'json-schema'
module Rswag module Rswag
module Specs module Specs
class ExtendedSchema < JSON::Schema::Validator class ExtendedSchema < JSON::Schema::Draft4
def initialize def initialize
super super
extend_schema_definition("http://json-schema.org/draft-04/schema#")
@attributes['type'] = ExtendedTypeAttribute @attributes['type'] = ExtendedTypeAttribute
@uri = URI.parse('http://tempuri.org/rswag/specs/extended_schema') @uri = URI.parse('http://tempuri.org/rswag/specs/extended_schema')
@names = ['http://tempuri.org/rswag/specs/extended_schema']
end end
end end
class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute
def self.validate(current_schema, data, fragments, processor, validator, options={}) def self.validate(current_schema, data, fragments, processor, validator, options={})
return if data.nil? && current_schema.schema['x-nullable'] == true return if data.nil? && current_schema.schema['x-nullable'] == true
super super

View File

@@ -33,13 +33,20 @@ module Rswag
end end
def build_headers(example) def build_headers(example)
headers = Hash[ parameters_in(:header).map { |p| [ p[:name], example.send(p[:name]).to_s ] } ] name_value_pairs = parameters_in(:header).map do |param|
headers.tap do |h| [
produces = @api_metadata[:operation][:produces] || @global_metadata[:produces] param[:name],
consumes = @api_metadata[:operation][:consumes] || @global_metadata[:consumes] example.send(param[:name]).to_s
h['ACCEPT'] = produces.join(';') unless produces.nil? ]
h['CONTENT_TYPE'] = consumes.join(';') unless consumes.nil?
end 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 end
private private
@@ -53,42 +60,48 @@ module Rswag
applicable_params applicable_params
.map { |p| p['$ref'] ? resolve_parameter(p['$ref']) : p } # resolve any references .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 } .select { |p| p[:in] == location }
end end
def resolve_parameter(ref) def resolve_parameter(ref)
defined_params = @global_metadata[:parameters] defined_params = @global_metadata[:parameters]
key = ref.sub('#/parameters/', '') key = ref.sub('#/parameters/', '')
raise "Referenced parameter '#{ref}' must be defined" unless defined_params && defined_params[key] raise "Referenced parameter '#{ref}' must be defined" unless defined_params && defined_params[key]
defined_params[key] defined_params[key]
end end
def resolve_api_key_parameters def security_parameters
@api_key_params ||= begin applicable_security_schemes.map do |scheme|
# First figure out the security requirement applicable to the operation if scheme[:type] == :apiKey
global_requirements = (@global_metadata[:security] || [] ).map { |r| r.keys.first } { name: scheme[:name], type: :string, in: scheme[:in] }
operation_requirements = (@api_metadata[:operation][:security] || [] ).map { |r| r.keys.first } else
requirements = global_requirements | operation_requirements { name: 'Authorization', type: :string, in: :header } # use auth header for basic & oauth2
end
# Then obtain the scheme definitions for those requirements
definitions = (@global_metadata[:securityDefinitions] || {}).slice(*requirements)
definitions.values.select { |d| d[:type] == :apiKey }
end 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) def build_query_string_part(param, value)
return "#{param[:name]}=#{value.to_s}" unless param[:type].to_sym == :array return "#{param[:name]}=#{value.to_s}" unless param[:type].to_sym == :array
name = param[:name] name = param[:name]
case param[:collectionFormat] case param[:collectionFormat]
when :ssv when :ssv
"#{name}=#{value.join(' ')}" "#{name}=#{value.join(' ')}"
when :tsv when :tsv
"#{name}=#{value.join('\t')}" "#{name}=#{value.join('\t')}"
when :pipes when :pipes
"#{name}=#{value.join('|')}" "#{name}=#{value.join('|')}"
when :multi when :multi
value.map { |v| "#{name}=#{v}" }.join('&') value.map { |v| "#{name}=#{v}" }.join('&')
else else
"#{name}=#{value.join(',')}" # csv is default "#{name}=#{value.join(',')}" # csv is default

View File

@@ -1,5 +1,5 @@
module Rswag module Rswag
module Specs module Specs
VERSION = '1.2.0' VERSION = '1.3.0'
end end
end end

View File

@@ -16,8 +16,7 @@ Gem::Specification.new do |s|
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 'activesupport', '>= 3.1'
s.add_dependency 'json', '~> 1.8' s.add_dependency 'railties', '>= 3.1'
s.add_dependency 'json-schema', '~> 2.2' s.add_dependency 'json-schema', '~> 2.2'
s.add_dependency 'rspec-rails', '>= 2.14', '< 4'
end end

View File

@@ -218,6 +218,33 @@ module Rswag
end end
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 context 'consumes & produces' do
before do before do
api_metadata[:operation][:consumes] = [ 'application/json', 'application/xml' ] api_metadata[:operation][:consumes] = [ 'application/json', 'application/xml' ]
@@ -226,8 +253,8 @@ module Rswag
it "includes corresponding 'Accept' & 'Content-Type' headers" do it "includes corresponding 'Accept' & 'Content-Type' headers" do
expect(headers).to match( expect(headers).to match(
'ACCEPT' => 'application/json;application/xml', 'Accept' => 'application/json;application/xml',
'CONTENT_TYPE' => 'application/json;application/xml' 'Content-Type' => 'application/json;application/xml'
) )
end end
end end
@@ -242,8 +269,8 @@ module Rswag
it "includes corresponding 'Accept' & 'Content-Type' headers" do it "includes corresponding 'Accept' & 'Content-Type' headers" do
expect(headers).to match( expect(headers).to match(
'ACCEPT' => 'application/json;application/xml', 'Accept' => 'application/json;application/xml',
'CONTENT_TYPE' => 'application/json;application/xml' 'Content-Type' => 'application/json;application/xml'
) )
end end
end end

View File

@@ -5,7 +5,14 @@ module Rswag
initializer 'rswag-ui.initialize' do |app| initializer 'rswag-ui.initialize' do |app|
if app.config.respond_to?(:assets) 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 end
end end

View File

@@ -1,5 +1,5 @@
module Rswag module Rswag
module Ui module Ui
VERSION = '1.2.0' VERSION = '1.3.0'
end end
end end

View File

@@ -16,5 +16,6 @@ Gem::Specification.new do |s|
s.files = Dir["{app,config,lib,vendor}/**/*"] + ["MIT-LICENSE", "Rakefile" ] 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 end

View File

@@ -1,3 +1,3 @@
module Rswag module Rswag
VERSION = '1.2.0' VERSION = '1.3.0'
end end

View File

@@ -1,7 +1,7 @@
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception. # Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead. # 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 ] wrap_parameters format: [ :json ]
end end

View 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

View File

@@ -5,7 +5,7 @@ class Blog < ActiveRecord::Base
{ {
id: id, id: id,
title: title, title: title,
content: content, content: nil,
thumbnail: thumbnail thumbnail: thumbnail
} }
end end

View File

@@ -1,5 +1,5 @@
require 'rubygems' require 'rubygems'
gemfile = File.expand_path('../../../../Gemfile', __FILE__) gemfile = File.expand_path('../../../Gemfile', __FILE__)
if File.exist?(gemfile) if File.exist?(gemfile)
ENV['BUNDLE_GEMFILE'] = gemfile ENV['BUNDLE_GEMFILE'] = gemfile
@@ -7,4 +7,4 @@ if File.exist?(gemfile)
Bundler.setup Bundler.setup
end end
$:.unshift File.expand_path('../../../../lib', __FILE__) $:.unshift File.expand_path('../../../../lib', __FILE__)

View File

@@ -28,4 +28,6 @@ TestApp::Application.configure do
# Expands the lines which load the assets # Expands the lines which load the assets
config.assets.debug = true config.assets.debug = true
config.eager_load = false
end end

View File

@@ -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

View File

@@ -32,4 +32,6 @@ TestApp::Application.configure do
# Print deprecation notices to the stderr # Print deprecation notices to the stderr
config.active_support.deprecation = :stderr config.active_support.deprecation = :stderr
config.eager_load = false
end end

View File

@@ -5,3 +5,6 @@
# Make sure the secret is at least 30 characters and all random, # Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks. # no regular words or you'll be exposed to dictionary attacks.
TestApp::Application.config.secret_token = '60f36cd33756d73f362053f1d45256ae50d75440b634ae73b070a6e35a2df38692f59e28e5ecbd1f9f2e850255f6d29a468bc59ac4484c2b7f0548ddbfc1b870' 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'

View File

@@ -2,6 +2,8 @@ TestApp::Application.routes.draw do
resources :blogs, defaults: { :format => :json } resources :blogs, defaults: { :format => :json }
put '/blogs/:id/upload', to: 'blogs#upload' put '/blogs/:id/upload', to: 'blogs#upload'
post 'auth-tests/basic', to: 'auth_tests#basic'
mount Rswag::Api::Engine => 'api-docs' mount Rswag::Api::Engine => 'api-docs'
mount Rswag::Ui::Engine => 'api-docs' mount Rswag::Ui::Engine => 'api-docs'
end end

View File

@@ -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 def change
create_table :blogs do |t| create_table :blogs do |t|
t.string :title t.string :title

View File

@@ -1,4 +1,3 @@
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead # 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 # of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition. # 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 # 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). # 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| create_table "blogs", force: :cascade do |t|
t.string "title" t.string "title", limit: 255
t.text "content" t.text "content"
t.string "thumbnail" t.string "thumbnail"
t.datetime "created_at", :null => false t.datetime "created_at", null: false
t.datetime "updated_at", :null => false t.datetime "updated_at", null: false
end end
end end

View 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

View File

@@ -39,13 +39,16 @@ RSpec.configure do |config|
properties: { properties: {
id: { type: 'integer' }, id: { type: 'integer' },
title: { type: 'string' }, title: { type: 'string' },
content: { type: 'string' }, content: { type: 'string', 'x-nullable': true },
thumbnail: { type: 'string'} thumbnail: { type: 'string'}
}, },
required: [ 'id', 'title', 'content', 'thumbnail' ] required: [ 'id', 'title', 'content', 'thumbnail' ]
} }
}, },
securityDefinitions: { securityDefinitions: {
basic_auth: {
type: :basic
},
api_key: { api_key: {
type: :apiKey, type: :apiKey,
name: 'api_key', name: 'api_key',

View File

@@ -5,6 +5,30 @@
"version": "v1" "version": "v1"
}, },
"paths": { "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": { "/blogs": {
"post": { "post": {
"summary": "Creates a blog", "summary": "Creates a blog",
@@ -192,7 +216,8 @@
"type": "string" "type": "string"
}, },
"content": { "content": {
"type": "string" "type": "string",
"x-nullable": true
}, },
"thumbnail": { "thumbnail": {
"type": "string" "type": "string"
@@ -207,6 +232,9 @@
} }
}, },
"securityDefinitions": { "securityDefinitions": {
"basic_auth": {
"type": "basic"
},
"api_key": { "api_key": {
"type": "apiKey", "type": "apiKey",
"name": "api_key", "name": "api_key",