mirror of
https://github.com/ditkrg/rswag.git
synced 2026-01-25 15:22:56 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf9170101b | ||
|
|
98d5b982c4 | ||
|
|
77d4cbe0ea | ||
|
|
32a7ab8234 | ||
|
|
95b009a72f | ||
|
|
471dff5e34 | ||
|
|
99be8135f7 | ||
|
|
8315eda8b2 | ||
|
|
e1fe9f3239 | ||
|
|
64b0de494f | ||
|
|
9d4069bcfe | ||
|
|
17a6cd13c4 | ||
|
|
0b0acfe4c7 | ||
|
|
5ea97a4278 | ||
|
|
5cf376891a | ||
|
|
10dd37896f | ||
|
|
3506fee3d0 | ||
|
|
5df130922f | ||
|
|
5a19cd2373 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
|||||||
**/*/log
|
**/*/log
|
||||||
**/*/*.gem
|
**/*/*.gem
|
||||||
**/*/*.sqlite3
|
**/*/*.sqlite3
|
||||||
|
**/*/public/assets
|
||||||
|
|||||||
@@ -7,4 +7,8 @@ env:
|
|||||||
- "RAILS_VERSION=5.0.0"
|
- "RAILS_VERSION=5.0.0"
|
||||||
cache: bundler
|
cache: bundler
|
||||||
install: bundle update
|
install: bundle update
|
||||||
|
before_script:
|
||||||
|
- "export DISPLAY=:99.0"
|
||||||
|
- "sh -e /etc/init.d/xvfb start"
|
||||||
|
- sleep 3 # give xvfb some time to start
|
||||||
script: ./ci/test.sh
|
script: ./ci/test.sh
|
||||||
|
|||||||
7
Gemfile
7
Gemfile
@@ -25,5 +25,12 @@ group :test do
|
|||||||
gem 'test-unit'
|
gem 'test-unit'
|
||||||
gem 'rspec-rails'
|
gem 'rspec-rails'
|
||||||
gem 'generator_spec'
|
gem 'generator_spec'
|
||||||
|
gem 'capybara'
|
||||||
|
gem 'capybara-webkit'
|
||||||
gem 'rswag-specs', path: './rswag-specs'
|
gem 'rswag-specs', path: './rswag-specs'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
group :assets do
|
||||||
|
gem 'uglifier'
|
||||||
|
gem 'therubyracer'
|
||||||
|
end
|
||||||
|
|||||||
33
Gemfile.lock
33
Gemfile.lock
@@ -1,13 +1,13 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: ./rswag-api
|
remote: ./rswag-api
|
||||||
specs:
|
specs:
|
||||||
rswag-api (1.0.1)
|
rswag-api (1.2.0)
|
||||||
rails (>= 3.1, < 5.1)
|
rails (>= 3.1, < 5.1)
|
||||||
|
|
||||||
PATH
|
PATH
|
||||||
remote: ./rswag-specs
|
remote: ./rswag-specs
|
||||||
specs:
|
specs:
|
||||||
rswag-specs (1.0.1)
|
rswag-specs (1.2.0)
|
||||||
json-schema (~> 2.2)
|
json-schema (~> 2.2)
|
||||||
rails (>= 3.1, < 5.1)
|
rails (>= 3.1, < 5.1)
|
||||||
rspec-rails (>= 2.14, < 4)
|
rspec-rails (>= 2.14, < 4)
|
||||||
@@ -15,7 +15,7 @@ PATH
|
|||||||
PATH
|
PATH
|
||||||
remote: ./rswag-ui
|
remote: ./rswag-ui
|
||||||
specs:
|
specs:
|
||||||
rswag-ui (1.0.1)
|
rswag-ui (1.2.0)
|
||||||
rails (>= 3.1, < 5.1)
|
rails (>= 3.1, < 5.1)
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
@@ -51,8 +51,19 @@ GEM
|
|||||||
addressable (2.4.0)
|
addressable (2.4.0)
|
||||||
arel (3.0.3)
|
arel (3.0.3)
|
||||||
builder (3.0.4)
|
builder (3.0.4)
|
||||||
|
capybara (2.10.1)
|
||||||
|
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)
|
||||||
|
json
|
||||||
diff-lcs (1.2.5)
|
diff-lcs (1.2.5)
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
|
execjs (2.7.0)
|
||||||
generator_spec (0.9.3)
|
generator_spec (0.9.3)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
@@ -62,11 +73,15 @@ GEM
|
|||||||
json (1.8.3)
|
json (1.8.3)
|
||||||
json-schema (2.7.0)
|
json-schema (2.7.0)
|
||||||
addressable (>= 2.4)
|
addressable (>= 2.4)
|
||||||
|
libv8 (3.16.14.15)
|
||||||
mail (2.5.4)
|
mail (2.5.4)
|
||||||
mime-types (~> 1.16)
|
mime-types (~> 1.16)
|
||||||
treetop (~> 1.4.8)
|
treetop (~> 1.4.8)
|
||||||
mime-types (1.25.1)
|
mime-types (1.25.1)
|
||||||
|
mini_portile2 (2.1.0)
|
||||||
multi_json (1.12.1)
|
multi_json (1.12.1)
|
||||||
|
nokogiri (1.6.8.1)
|
||||||
|
mini_portile2 (~> 2.1.0)
|
||||||
polyglot (0.3.5)
|
polyglot (0.3.5)
|
||||||
power_assert (0.3.1)
|
power_assert (0.3.1)
|
||||||
rack (1.4.7)
|
rack (1.4.7)
|
||||||
@@ -94,6 +109,7 @@ GEM
|
|||||||
rake (11.3.0)
|
rake (11.3.0)
|
||||||
rdoc (3.12.2)
|
rdoc (3.12.2)
|
||||||
json (~> 1.4)
|
json (~> 1.4)
|
||||||
|
ref (2.0.0)
|
||||||
rspec-core (3.5.4)
|
rspec-core (3.5.4)
|
||||||
rspec-support (~> 3.5.0)
|
rspec-support (~> 3.5.0)
|
||||||
rspec-expectations (3.5.0)
|
rspec-expectations (3.5.0)
|
||||||
@@ -124,17 +140,26 @@ GEM
|
|||||||
railties (~> 3.0)
|
railties (~> 3.0)
|
||||||
test-unit (3.2.1)
|
test-unit (3.2.1)
|
||||||
power_assert
|
power_assert
|
||||||
|
therubyracer (0.12.2)
|
||||||
|
libv8 (~> 3.16.14.0)
|
||||||
|
ref
|
||||||
thor (0.19.1)
|
thor (0.19.1)
|
||||||
tilt (1.4.1)
|
tilt (1.4.1)
|
||||||
treetop (1.4.15)
|
treetop (1.4.15)
|
||||||
polyglot
|
polyglot
|
||||||
polyglot (>= 0.3.1)
|
polyglot (>= 0.3.1)
|
||||||
tzinfo (0.3.51)
|
tzinfo (0.3.51)
|
||||||
|
uglifier (3.0.2)
|
||||||
|
execjs (>= 0.3.0, < 3)
|
||||||
|
xpath (2.0.0)
|
||||||
|
nokogiri (~> 1.3)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
capybara
|
||||||
|
capybara-webkit
|
||||||
generator_spec
|
generator_spec
|
||||||
rails (= 3.2.22)
|
rails (= 3.2.22)
|
||||||
rspec-rails
|
rspec-rails
|
||||||
@@ -144,3 +169,5 @@ DEPENDENCIES
|
|||||||
sqlite3
|
sqlite3
|
||||||
strong_parameters
|
strong_parameters
|
||||||
test-unit
|
test-unit
|
||||||
|
therubyracer
|
||||||
|
uglifier
|
||||||
|
|||||||
61
README.md
61
README.md
@@ -171,8 +171,8 @@ The steps described above will get you up and running with minimal setup. Howeve
|
|||||||
|Gem|Description|Added/Updated|
|
|Gem|Description|Added/Updated|
|
||||||
|---------|-----------|-------------|
|
|---------|-----------|-------------|
|
||||||
|__rswag-specs__|Swagger-based DSL for rspec & accompanying rake task for generating Swagger files|_spec/swagger_helper.rb_|
|
|__rswag-specs__|Swagger-based DSL for rspec & accompanying rake task for generating Swagger files|_spec/swagger_helper.rb_|
|
||||||
|__rswag-api__ |Rails Engine that exposes the Swagger files as JSON endpoints|_config/initializers/rswag-api.rb, config/routes.rb_|
|
|__rswag-api__ |Rails Engine that exposes your Swagger files as JSON endpoints|_config/initializers/rswag-api.rb, config/routes.rb_|
|
||||||
|__rswag-ui__ |Rails Engine that includes [swagger-ui](https://github.com/swagger-api/swagger-ui) and powers it from the Swagger endpoints|_config/initializers/rswag-ui.rb, config/routes.rb_|
|
|__rswag-ui__ |Rails Engine that includes [swagger-ui](https://github.com/swagger-api/swagger-ui) and powers it from your Swagger endpoints|_config/initializers/rswag-ui.rb, config/routes.rb_|
|
||||||
|
|
||||||
### Output Location for Generated Swagger Files ###
|
### Output Location for Generated Swagger Files ###
|
||||||
|
|
||||||
@@ -243,6 +243,63 @@ describe 'Blogs API' do
|
|||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Response headers ###
|
||||||
|
|
||||||
|
In Rswag, you could use `header` method inside the response block to specify header objects for this response. Rswag will validate your response headers with those header objects and inject them into the generated swagger file:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
# spec/integration/comments_spec.rb
|
||||||
|
describe 'Blogs API' do
|
||||||
|
|
||||||
|
path '/blogs/{blog_id}/comments' do
|
||||||
|
|
||||||
|
post 'Creates a comment' do
|
||||||
|
|
||||||
|
response 422, 'invalid request' do
|
||||||
|
header 'X-Rate-Limit-Limit', type: :integer, description: 'The number of allowed requests in the current period'
|
||||||
|
header 'X-Rate-Limit-Remaining', type: :integer, description: 'The number of remaining requests in the current period'
|
||||||
|
...
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response examples ###
|
||||||
|
|
||||||
|
You can provide custom response examples to the generated swagger file by calling the method `examples` inside the response block:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
# spec/integration/blogs_spec.rb
|
||||||
|
describe 'Blogs API' do
|
||||||
|
|
||||||
|
path '/blogs/{blog_id}' do
|
||||||
|
|
||||||
|
get 'Retrieves a blog' do
|
||||||
|
|
||||||
|
response 200, 'blog found' do
|
||||||
|
examples 'application/json' => {
|
||||||
|
id: 1,
|
||||||
|
title: 'Hello world!',
|
||||||
|
content: '...'
|
||||||
|
}
|
||||||
|
...
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enable generation examples from responses ###
|
||||||
|
|
||||||
|
To enable examples generation from responses add callback above run_test! like:
|
||||||
|
```ruby
|
||||||
|
after do |example|
|
||||||
|
example.metadata[:response][:examples] = { 'application/json' => JSON.parse(response.body, symbolize_names: true) }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
You need to disable --dry-run option for Rspec > 3
|
||||||
|
|
||||||
|
Add to application.rb:
|
||||||
|
```ruby
|
||||||
|
RSpec.configure do |config|
|
||||||
|
config.swagger_dry_run = false
|
||||||
|
end
|
||||||
|
```
|
||||||
### Route Prefix for Swagger JSON Endpoints ###
|
### Route Prefix for Swagger JSON Endpoints ###
|
||||||
|
|
||||||
The functionality to expose Swagger files, such as those generated by rswag-specs, as JSON endpoints is implemented as a Rails Engine. As with any Engine, you can change it's mount prefix in _routes.rb_:
|
The functionality to expose Swagger files, such as those generated by rswag-specs, as JSON endpoints is implemented as a Rails Engine. As with any Engine, you can change it's mount prefix in _routes.rb_:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
module Rswag
|
module Rswag
|
||||||
module Api
|
module Api
|
||||||
VERSION = '1.0.2'
|
VERSION = '1.2.0'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ module Rswag
|
|||||||
::RSpec.configure do |c|
|
::RSpec.configure do |c|
|
||||||
c.add_setting :swagger_root
|
c.add_setting :swagger_root
|
||||||
c.add_setting :swagger_docs
|
c.add_setting :swagger_docs
|
||||||
|
c.add_setting :swagger_dry_run
|
||||||
c.extend ExampleGroupHelpers, type: :request
|
c.extend ExampleGroupHelpers, type: :request
|
||||||
c.include ExampleHelpers, type: :request
|
c.include ExampleHelpers, type: :request
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ module Rswag
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def swagger_dry_run
|
||||||
|
@swagger_dry_run ||= begin
|
||||||
|
@rspec_config.swagger_dry_run.nil? || @rspec_config.swagger_dry_run
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_swagger_doc(name)
|
def get_swagger_doc(name)
|
||||||
return swagger_docs.values.first if name.nil?
|
return swagger_docs.values.first if name.nil?
|
||||||
raise ConfigurationError, "Unknown swagger_doc '#{name}'" unless swagger_docs[name]
|
raise ConfigurationError, "Unknown swagger_doc '#{name}'" unless swagger_docs[name]
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ module Rswag
|
|||||||
metadata[:response][:headers][name] = attributes
|
metadata[:response][:headers][name] = attributes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# NOTE: Similar to 'description', 'examples' need to handle the case when
|
||||||
|
# being invoked with no params to avoid overriding 'examples' method of
|
||||||
|
# rspec-core ExampleGroup
|
||||||
|
def examples(example = nil)
|
||||||
|
return super() if example.nil?
|
||||||
|
metadata[:response][:examples] = example
|
||||||
|
end
|
||||||
|
|
||||||
def run_test!
|
def run_test!
|
||||||
# NOTE: rspec 2.x support
|
# NOTE: rspec 2.x support
|
||||||
if RSPEC_VERSION < 3
|
if RSPEC_VERSION < 3
|
||||||
|
|||||||
25
rswag-specs/lib/rswag/specs/extended_schema.rb
Normal file
25
rswag-specs/lib/rswag/specs/extended_schema.rb
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
require 'json-schema'
|
||||||
|
|
||||||
|
module Rswag
|
||||||
|
module Specs
|
||||||
|
class ExtendedSchema < JSON::Schema::Validator
|
||||||
|
|
||||||
|
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')
|
||||||
|
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
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
JSON::Validator.register_validator(ExtendedSchema.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
|
require 'active_support/core_ext/hash/slice'
|
||||||
require 'json-schema'
|
require 'json-schema'
|
||||||
|
require 'rswag/specs/extended_schema'
|
||||||
|
|
||||||
module Rswag
|
module Rswag
|
||||||
module Specs
|
module Specs
|
||||||
@@ -11,6 +13,7 @@ module Rswag
|
|||||||
|
|
||||||
def validate!(response)
|
def validate!(response)
|
||||||
validate_code!(response.code)
|
validate_code!(response.code)
|
||||||
|
validate_headers!(response.headers)
|
||||||
validate_body!(response.body)
|
validate_body!(response.body)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -22,11 +25,24 @@ module Rswag
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_headers!(headers)
|
||||||
|
header_schema = @api_metadata[:response][:headers]
|
||||||
|
return if header_schema.nil?
|
||||||
|
|
||||||
|
header_schema.keys.each do |header_name|
|
||||||
|
raise UnexpectedResponse, "Expected response header #{header_name} to be present" if headers[header_name.to_s].nil?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def validate_body!(body)
|
def validate_body!(body)
|
||||||
schema = @api_metadata[:response][:schema]
|
response_schema = @api_metadata[:response][:schema]
|
||||||
return if schema.nil?
|
return if response_schema.nil?
|
||||||
|
|
||||||
begin
|
begin
|
||||||
JSON::Validator.validate!(schema.merge(@global_metadata), body)
|
validation_schema = response_schema
|
||||||
|
.merge('$schema' => 'http://tempuri.org/rswag/specs/extended_schema')
|
||||||
|
.merge(@global_metadata.slice(:definitions))
|
||||||
|
JSON::Validator.validate!(validation_schema, body)
|
||||||
rescue JSON::Schema::ValidationError => ex
|
rescue JSON::Schema::ValidationError => ex
|
||||||
raise UnexpectedResponse, "Expected response body to match schema: #{ex.message}"
|
raise UnexpectedResponse, "Expected response body to match schema: #{ex.message}"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
module Rswag
|
module Rswag
|
||||||
module Specs
|
module Specs
|
||||||
VERSION = '1.0.2'
|
VERSION = '1.2.0'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace :rswag do
|
|||||||
t.pattern = 'spec/requests/**/*_spec.rb, spec/api/**/*_spec.rb, spec/integration/**/*_spec.rb'
|
t.pattern = 'spec/requests/**/*_spec.rb, spec/api/**/*_spec.rb, spec/integration/**/*_spec.rb'
|
||||||
|
|
||||||
# NOTE: rspec 2.x support
|
# NOTE: rspec 2.x support
|
||||||
if Rswag::Specs::RSPEC_VERSION > 2
|
if Rswag::Specs::RSPEC_VERSION > 2 && Rswag::Specs.config.swagger_dry_run
|
||||||
t.rspec_opts = [ '--format Rswag::Specs::SwaggerFormatter', '--dry-run', '--order defined' ]
|
t.rspec_opts = [ '--format Rswag::Specs::SwaggerFormatter', '--dry-run', '--order defined' ]
|
||||||
else
|
else
|
||||||
t.rspec_opts = [ '--format Rswag::Specs::SwaggerFormatter', '--order defined' ]
|
t.rspec_opts = [ '--format Rswag::Specs::SwaggerFormatter', '--order defined' ]
|
||||||
|
|||||||
@@ -151,6 +151,25 @@ module Rswag
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#examples(example)' do
|
||||||
|
let(:json_example) do
|
||||||
|
{
|
||||||
|
'application/json' => {
|
||||||
|
foo: 'bar'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let(:api_metadata) { { response: {} } }
|
||||||
|
|
||||||
|
before do
|
||||||
|
subject.examples(json_example)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "adds to the 'response examples' metadata" do
|
||||||
|
expect(api_metadata[:response][:examples]).to eq(json_example)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -66,6 +66,42 @@ module Rswag
|
|||||||
it { expect { call }.to raise_error UnexpectedResponse }
|
it { expect { call }.to raise_error UnexpectedResponse }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "'headers' provided" do
|
||||||
|
before do
|
||||||
|
api_metadata[:response][:headers] = {
|
||||||
|
'X-Rate-Limit-Limit' => {
|
||||||
|
description: 'The number of allowed requests in the current period',
|
||||||
|
type: 'integer'
|
||||||
|
},
|
||||||
|
'X-Rate-Limit-Remaining' => {
|
||||||
|
description: 'The number of remaining requests in the current period',
|
||||||
|
type: 'integer'
|
||||||
|
},
|
||||||
|
'X-Rate-Limit-Reset' => {
|
||||||
|
description: 'The number of seconds left in the current period',
|
||||||
|
type: 'integer'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'response code & body matches' do
|
||||||
|
let(:response) { OpenStruct.new(code: 200, body: '{}', headers: {
|
||||||
|
'X-Rate-Limit-Limit' => 1,
|
||||||
|
'X-Rate-Limit-Remaining' => 1,
|
||||||
|
'X-Rate-Limit-Reset' => 1
|
||||||
|
}) }
|
||||||
|
it { expect { call }.to_not raise_error }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'response code matches & body does not' do
|
||||||
|
let(:response) { OpenStruct.new(code: 200, body: '{}', headers: {
|
||||||
|
'X-Rate-Limit-Limit' => 1,
|
||||||
|
'X-Rate-Limit-Remaining' => 1
|
||||||
|
}) }
|
||||||
|
it { expect { call }.to raise_error UnexpectedResponse }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,33 +3,33 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Swagger UI</title>
|
<title>Swagger UI</title>
|
||||||
<link rel="icon" type="image/png" href="/assets/swagger-ui/images/favicon-32x32.png" sizes="32x32" />
|
<link rel="icon" type="image/png" href="<%= asset_path 'swagger-ui/images/favicon-32x32.png' %>" sizes="32x32" />
|
||||||
<link rel="icon" type="image/png" href="/assets/swagger-ui/images/favicon-16x16.png" sizes="16x16" />
|
<link rel="icon" type="image/png" href="<%= asset_path 'swagger-ui/images/favicon-16x16.png' %>" sizes="16x16" />
|
||||||
<link href='/assets/swagger-ui/css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
|
<link href="<%= asset_path 'swagger-ui/css/typography.css' %>" media='screen' rel='stylesheet' type='text/css'/>
|
||||||
<link href='/assets/swagger-ui/css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
|
<link href="<%= asset_path 'swagger-ui/css/reset.css' %>" media='screen' rel='stylesheet' type='text/css'/>
|
||||||
<link href='/assets/swagger-ui/css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
|
<link href="<%= asset_path 'swagger-ui/css/screen.css' %>" media='screen' rel='stylesheet' type='text/css'/>
|
||||||
<link href='/assets/swagger-ui/css/reset.css' media='print' rel='stylesheet' type='text/css'/>
|
<link href="<%= asset_path 'swagger-ui/css/reset.css' %>" media='print' rel='stylesheet' type='text/css'/>
|
||||||
<link href='/assets/swagger-ui/css/print.css' media='print' rel='stylesheet' type='text/css'/>
|
<link href="<%= asset_path 'swagger-ui/css/print.css' %>" media='print' rel='stylesheet' type='text/css'/>
|
||||||
|
|
||||||
<script src='/assets/swagger-ui/lib/object-assign-pollyfill.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/object-assign-pollyfill.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/jquery-1.8.0.min.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/jquery-1.8.0.min.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/jquery.slideto.min.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/jquery.slideto.min.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/jquery.wiggle.min.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/jquery.wiggle.min.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/jquery.ba-bbq.min.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/handlebars-4.0.5.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/handlebars-4.0.5.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/lodash.min.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/lodash.min.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/backbone-min.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/backbone-min.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/swagger-ui.min.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/swagger-ui.min.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/highlight.9.1.0.pack.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/highlight.9.1.0.pack_extended.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/highlight.9.1.0.pack_extended.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/jsoneditor.min.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/jsoneditor.min.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/marked.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/marked.js' %>" type='text/javascript'></script>
|
||||||
<script src='/assets/swagger-ui/lib/swagger-oauth.js' type='text/javascript'></script>
|
<script src="<%= asset_path 'swagger-ui/lib/swagger-oauth.js' %>" type='text/javascript'></script>
|
||||||
|
|
||||||
<!-- Some basic translations -->
|
<!-- Some basic translations -->
|
||||||
<!-- <script src='/assets/swagger-ui/lang/translator.js' type='text/javascript'></script> -->
|
<!-- <script src="<%= asset_path 'swagger-ui/lang/translator.js' %>" type='text/javascript'></script> -->
|
||||||
<!-- <script src='/assets/swagger-ui/lang/ru.js' type='text/javascript'></script> -->
|
<!-- <script src="<%= asset_path 'swagger-ui/lang/ru.js' %>" type='text/javascript'></script> -->
|
||||||
<!-- <script src='/assets/swagger-ui/lang/en.js' type='text/javascript'></script> -->
|
<!-- <script src="<%= asset_path 'swagger-ui/lang/en.js' %>" type='text/javascript'></script> -->
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function () {
|
$(function () {
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
<body class="swagger-section">
|
<body class="swagger-section">
|
||||||
<div id='header'>
|
<div id='header'>
|
||||||
<div class="swagger-ui-wrap">
|
<div class="swagger-ui-wrap">
|
||||||
<a id="logo" href="http://swagger.io"><img class="logo__img" alt="swagger" height="30" width="30" src="/assets/swagger-ui/images/logo_small.png" /><span class="logo__title">swagger</span></a>
|
<a id="logo" href="http://swagger.io"><img class="logo__img" alt="swagger" height="30" width="30" src="<%= asset_path 'swagger-ui/images/logo_small.png' %>" /><span class="logo__title">swagger</span></a>
|
||||||
<form id='api_selector'>
|
<form id='api_selector'>
|
||||||
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/></div>
|
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/></div>
|
||||||
<div id='auth_container'></div>
|
<div id='auth_container'></div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
module Rswag
|
module Rswag
|
||||||
module Ui
|
module Ui
|
||||||
VERSION = '1.0.2'
|
VERSION = '1.2.0'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -880,7 +880,7 @@
|
|||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
}
|
}
|
||||||
.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber {
|
.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber {
|
||||||
background-image: url('../images/throbber.gif');
|
background-image: url(<%= asset_path('swagger-ui/images/throbber.gif') %>);
|
||||||
width: 128px;
|
width: 128px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
display: block;
|
display: block;
|
||||||
@@ -1222,7 +1222,7 @@
|
|||||||
height: 18px;
|
height: 18px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: url(../images/explorer_icons.png) no-repeat;
|
background: url(<%= asset_path('swagger-ui/images/explorer_icons.png') %>) no-repeat;
|
||||||
}
|
}
|
||||||
.swagger-section .authorize__btn_operation_login {
|
.swagger-section .authorize__btn_operation_login {
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
@@ -880,7 +880,7 @@
|
|||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
}
|
}
|
||||||
.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber {
|
.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber {
|
||||||
background-image: url('../images/throbber.gif');
|
background-image: url(<%= asset_path('swagger-ui/images/throbber.gif') %>);
|
||||||
width: 128px;
|
width: 128px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
display: block;
|
display: block;
|
||||||
@@ -1222,7 +1222,7 @@
|
|||||||
height: 18px;
|
height: 18px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: url(../images/explorer_icons.png) no-repeat;
|
background: url(<%= asset_path('swagger-ui/images/explorer_icons.png') %>) no-repeat;
|
||||||
}
|
}
|
||||||
.swagger-section .authorize__btn_operation_login {
|
.swagger-section .authorize__btn_operation_login {
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
@@ -1354,7 +1354,7 @@
|
|||||||
height: 18px;
|
height: 18px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: url(../images/explorer_icons.png) no-repeat;
|
background: url(<%= asset_path('swagger-ui/images/explorer_icons.png') %>) no-repeat;
|
||||||
}
|
}
|
||||||
.swagger-section .api-ic .api_information_panel {
|
.swagger-section .api-ic .api_information_panel {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background: transparent url(../images/logo.png) no-repeat left center;
|
background: transparent url(<%= asset_path('swagger-ui/images/logo.png') %>) no-repeat left center;
|
||||||
padding: 20px 0 20px 40px;
|
padding: 20px 0 20px 40px;
|
||||||
}
|
}
|
||||||
#text-head {
|
#text-head {
|
||||||
@@ -64,7 +64,7 @@ h1 {
|
|||||||
width: 1500px;
|
width: 1500px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
background-image: url('../images/shield.png');
|
background-image: url(<%= asset_path('swagger-ui/images/shield.png') %>);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: -40px -20px;
|
background-position: -40px -20px;
|
||||||
margin-bottom: 210px;
|
margin-bottom: 210px;
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
/* Google Font's Droid Sans */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Droid Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Droid Sans'), local('DroidSans'), url('../fonts/DroidSans.ttf'), format('truetype');
|
|
||||||
}
|
|
||||||
/* Google Font's Droid Sans Bold */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Droid Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Droid Sans Bold'), local('DroidSans-Bold'), url('../fonts/DroidSans-Bold.ttf'), format('truetype');
|
|
||||||
}
|
|
||||||
14
rswag-ui/vendor/assets/components/swagger-ui/css/typography.css.erb
vendored
Normal file
14
rswag-ui/vendor/assets/components/swagger-ui/css/typography.css.erb
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/* Google Font's Droid Sans */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Droid Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Droid Sans'), local('DroidSans'), url(<%= asset_path('swagger-ui/fonts/DroidSans.ttf') %>), format('truetype');
|
||||||
|
}
|
||||||
|
/* Google Font's Droid Sans Bold */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Droid Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Droid Sans Bold'), local('DroidSans-Bold'), url(<%= asset_path('swagger-ui/fonts/DroidSans-Bold.ttf') %>), format('truetype');
|
||||||
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
module Rswag
|
module Rswag
|
||||||
VERSION = '1.0.2'
|
VERSION = '1.2.0'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ class BlogsController < ApplicationController
|
|||||||
# GET /blogs/1
|
# GET /blogs/1
|
||||||
def show
|
def show
|
||||||
@blog = Blog.find_by_id(params[:id])
|
@blog = Blog.find_by_id(params[:id])
|
||||||
|
|
||||||
|
fresh_when(@blog)
|
||||||
|
return unless stale?(@blog)
|
||||||
|
|
||||||
respond_with @blog, status: :not_found and return unless @blog
|
respond_with @blog, status: :not_found and return unless @blog
|
||||||
respond_with @blog
|
respond_with @blog
|
||||||
end
|
end
|
||||||
|
|||||||
67
test-app/config/environments/production.rb
Normal file
67
test-app/config/environments/production.rb
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
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
|
||||||
12
test-app/spec/features/swagger_ui_spec.rb
Normal file
12
test-app/spec/features/swagger_ui_spec.rb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
feature 'swagger-ui', js: true do
|
||||||
|
|
||||||
|
scenario 'browsing api-docs' do
|
||||||
|
visit '/api-docs'
|
||||||
|
|
||||||
|
expect(page).to have_content('GET /blogs Searches blogs')
|
||||||
|
expect(page).to have_content('POST /blogs Creates a blog')
|
||||||
|
expect(page).to have_content('GET /blogs/{id} Retrieves a blog')
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -50,8 +50,18 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
|
|||||||
produces 'application/json'
|
produces 'application/json'
|
||||||
|
|
||||||
response '200', 'blog found' do
|
response '200', 'blog found' do
|
||||||
|
header 'ETag', type: :string
|
||||||
|
header 'Last-Modified', type: :string
|
||||||
|
header 'Cache-Control', type: :string
|
||||||
|
|
||||||
schema '$ref' => '#/definitions/blog'
|
schema '$ref' => '#/definitions/blog'
|
||||||
|
|
||||||
|
examples 'application/json' => {
|
||||||
|
id: 1,
|
||||||
|
title: 'Hello world!',
|
||||||
|
content: 'Hello world and hello universe. Thank you all very much!!!'
|
||||||
|
}
|
||||||
|
|
||||||
let(:blog) { Blog.create(title: 'foo', content: 'bar') }
|
let(:blog) { Blog.create(title: 'foo', content: 'bar') }
|
||||||
let(:id) { blog.id }
|
let(:id) { blog.id }
|
||||||
run_test!
|
run_test!
|
||||||
|
|||||||
@@ -50,4 +50,6 @@ RSpec.configure do |config|
|
|||||||
config.filter_rails_from_backtrace!
|
config.filter_rails_from_backtrace!
|
||||||
# arbitrary gems may also be filtered via:
|
# arbitrary gems may also be filtered via:
|
||||||
# config.filter_gems_from_backtrace("gem name")
|
# config.filter_gems_from_backtrace("gem name")
|
||||||
|
|
||||||
|
Capybara.javascript_driver = :webkit
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -89,8 +89,26 @@
|
|||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "blog found",
|
"description": "blog found",
|
||||||
|
"headers": {
|
||||||
|
"ETag": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Last-Modified": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Cache-Control": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/blog"
|
"$ref": "#/definitions/blog"
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"application/json": {
|
||||||
|
"id": 1,
|
||||||
|
"title": "Hello world!",
|
||||||
|
"content": "Hello world and hello universe. Thank you all very much!!!"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
|
|||||||
Reference in New Issue
Block a user