Merge branch 'master' of github.com:rswag/rswag

This commit is contained in:
Laura Watson 2019-10-17 13:34:54 +01:00
commit 71423cffb6
27 changed files with 211 additions and 38 deletions

View File

@ -12,15 +12,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
### Security
## [2.1.0] - 2019-10-17
### Added
- New Spec Generator [#75](https://github.com/rswag/rswag/pull/75)
- Support for Options and Trace verbs; You must use a framework that supports this, for Options Rails 6.1+ Rails 6 does not support Trace. [#237](https://github.com/rswag/rswag/pull/75)
### Changed
- Update swagger-ui to 3.18.2 [#240](https://github.com/rswag/rswag/pull/240)
## [2.0.6] - 2019-10-03
### Added
- Support for Rails 6 [#228](https://github.com/rswag/rswag/pull/228)
- Support for Windows paths [#176](https://github.com/rswag/rswag/pull/176)
### Changed
- Show response body when error code is not expected [#117](https://github.com/rswag/rswag/pull/177)
### Deprecated
### Removed
### Fixed
### Security
## [2.0.5] - 2018-07-10

View File

@ -14,8 +14,8 @@ Once you have an API that can describe itself in Swagger, you've opened the trea
|Rswag Version|Swagger (OpenAPI) Spec.|swagger-ui|
|----------|----------|----------|
|[master](https://github.com/rswag/rswag/tree/master)|2.0|3.17.3|
|[2.0.6](https://github.com/rswag/rswag/tree/2.0.6)|2.0|3.17.3|
|[master](https://github.com/rswag/rswag/tree/master)|2.0|3.18.2|
|[2.1.0](https://github.com/rswag/rswag/tree/2.1.0)|2.0|3.18.2|
|[1.6.0](https://github.com/rswag/rswag/tree/1.6.0)|2.0|2.2.5|
## Getting Started ##
@ -48,7 +48,8 @@ Once you have an API that can describe itself in Swagger, you've opened the trea
Or run the install generators for each package separately if you installed Rswag as separate gems, as indicated above:
```ruby
rails g rswag:api:install rswag:ui:install
rails g rswag:api:install
rails g rswag:ui:install
RAILS_ENV=test rails g rswag:specs:install
```

View File

@ -0,0 +1,9 @@
Description:
This creates an RSpec request spec to define Swagger documentation for a
controller. It will create a test for each of the controller's methods.
Example:
rails generate rspec:swagger V3::AccountsController
This will create:
spec/requests/v3/accounts_spec.rb

View File

@ -0,0 +1,22 @@
require 'rswag/route_parser'
require 'rails/generators'
module Rspec
class SwaggerGenerator < ::Rails::Generators::NamedBase
source_root File.expand_path('../templates', __FILE__)
def setup
@routes = Rswag::RouteParser.new(controller_path).routes
end
def create_spec_file
template 'spec.rb', File.join('spec', 'requests', "#{controller_path}_spec.rb")
end
private
def controller_path
file_path.chomp('_controller')
end
end
end

View File

@ -0,0 +1,30 @@
require 'swagger_helper'
RSpec.describe '<%= controller_path %>', type: :request do
<% @routes.each do | template, path_item | %>
path '<%= template %>' do
<% unless path_item[:params].empty? -%>
# You'll want to customize the parameter types...
<% path_item[:params].each do |param| -%>
parameter name: '<%= param %>', in: :path, type: :string, description: '<%= param %>'
<% end -%>
<% end -%>
<% path_item[:actions].each do | action, details | %>
<%= action %>('<%= details[:summary] %>') do
response(200, 'successful') do
<% unless path_item[:params].empty? -%>
<% path_item[:params].each do |param| -%>
let(:<%= param %>) { '123' }
<% end -%>
<% end -%>
after do |example|
example.metadata[:response][:examples] = { 'application/json' => JSON.parse(response.body, symbolize_names: true) }
end
run_test!
end
end
<% end -%>
end
<% end -%>
end

View File

@ -0,0 +1,58 @@
module Rswag
class RouteParser
attr_reader :controller
def initialize(controller)
@controller = controller
end
def routes
::Rails.application.routes.routes.select do |route|
route.defaults[:controller] == controller
end.reduce({}) do |tree, route|
path = path_from(route)
verb = verb_from(route)
tree[path] ||= { params: params_from(route), actions: {} }
tree[path][:actions][verb] = { summary: summary_from(route) }
tree
end
end
private
def path_from(route)
route.path.spec.to_s
.chomp('(.:format)') # Ignore any format suffix
.gsub(/:([^\/.?]+)/, '{\1}') # Convert :id to {id}
end
def verb_from(route)
verb = route.verb
if verb.kind_of? String
verb.downcase
else
verb.source.gsub(/[$^]/, '').downcase
end
end
def summary_from(route)
verb = route.requirements[:action]
noun = route.requirements[:controller].split('/').last.singularize
# Apply a few customizations to make things more readable
case verb
when 'index'
verb = 'list'
noun = noun.pluralize
when 'destroy'
verb = 'delete'
end
"#{verb} #{noun}"
end
def params_from(route)
route.segments - ['format']
end
end
end

View File

@ -3,7 +3,7 @@ require 'json-schema'
module Rswag
module Specs
class ExtendedSchema < JSON::Schema::Draft4
def initialize
super
@attributes['type'] = ExtendedTypeAttribute
@ -13,7 +13,7 @@ module Rswag
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

View File

@ -5,6 +5,10 @@ module Rswag
rake_tasks do
load File.expand_path('../../../tasks/rswag-specs_tasks.rake', __FILE__)
end
generators do
require 'generators/rspec/swagger/swagger_generator.rb'
end
end
end
end

View File

@ -54,7 +54,7 @@ module Rswag
definitions[key]
end
def add_verb(request, metadata)
def add_verb(request, metadata)
request[:verb] = metadata[:operation][:verb]
end
@ -104,7 +104,7 @@ module Rswag
end
# Content-Type header
consumes = metadata[:operation][:consumes] || swagger_doc[:consumes]
consumes = metadata[:operation][:consumes] || swagger_doc[:consumes]
if consumes
content_type = example.respond_to?(:'Content-Type') ? example.send(:'Content-Type') : consumes.first
tuples << [ 'Content-Type', content_type ]

View File

@ -0,0 +1,44 @@
require 'generator_spec'
require 'generators/rspec/swagger_generator'
require 'tmpdir'
module Rspec
describe SwaggerGenerator do
include GeneratorSpec::TestCase
destination Dir.mktmpdir
before(:all) do
prepare_destination
fixtures_dir = File.expand_path('../fixtures', __FILE__)
FileUtils.cp_r("#{fixtures_dir}/spec", destination_root)
end
after(:all) do
end
it 'installs the swagger_helper for rspec' do
allow_any_instance_of(Rswag::RouteParser).to receive(:routes).and_return(fake_routes)
run_generator ['Posts::CommentsController']
assert_file('spec/requests/posts/comments_spec.rb') do |content|
assert_match(/parameter name: 'post_id', in: :path, type: :string/, content)
assert_match(/patch\('update_comments comment'\)/, content)
end
end
private
def fake_routes
{
"/posts/{post_id}/comments/{id}" => {
:params => ["post_id", "id"],
:actions => {
"get" => { :summary=>"show comment" },
"patch" => { :summary=>"update_comments comment" }
}
}
}
end
end
end

View File

@ -4,7 +4,7 @@ require 'generators/rswag/specs/install/install_generator'
module Rswag
module Specs
describe InstallGenerator do
RSpec.describe InstallGenerator do
include GeneratorSpec::TestCase
destination File.expand_path('../tmp', __FILE__)

View File

@ -3,7 +3,7 @@ require 'rswag/specs/configuration'
module Rswag
module Specs
describe Configuration do
RSpec.describe Configuration do
subject { described_class.new(rspec_config) }
let(:rspec_config) { OpenStruct.new(swagger_root: swagger_root, swagger_docs: swagger_docs) }

View File

@ -3,7 +3,7 @@ require 'rswag/specs/example_group_helpers'
module Rswag
module Specs
describe ExampleGroupHelpers do
RSpec.describe ExampleGroupHelpers do
subject { double('example_group') }
before do

View File

@ -3,7 +3,7 @@ require 'rswag/specs/example_helpers'
module Rswag
module Specs
describe ExampleHelpers do
RSpec.describe ExampleHelpers do
subject { double('example') }
before do
@ -12,7 +12,7 @@ module Rswag
allow(config).to receive(:get_swagger_doc).and_return(swagger_doc)
stub_const('Rswag::Specs::RAILS_VERSION', 3)
end
let(:config) { double('config') }
let(:config) { double('config') }
let(:swagger_doc) do
{
securityDefinitions: {

View File

@ -3,13 +3,13 @@ require 'rswag/specs/request_factory'
module Rswag
module Specs
describe RequestFactory do
RSpec.describe RequestFactory do
subject { RequestFactory.new(config) }
before do
allow(config).to receive(:get_swagger_doc).and_return(swagger_doc)
end
let(:config) { double('config') }
let(:config) { double('config') }
let(:swagger_doc) { {} }
let(:example) { double('example') }
let(:metadata) do

View File

@ -3,13 +3,13 @@ require 'rswag/specs/response_validator'
module Rswag
module Specs
describe ResponseValidator do
RSpec.describe ResponseValidator do
subject { ResponseValidator.new(config) }
before do
allow(config).to receive(:get_swagger_doc).and_return(swagger_doc)
end
let(:config) { double('config') }
let(:config) { double('config') }
let(:swagger_doc) { {} }
let(:example) { double('example') }
let(:metadata) do

View File

@ -3,8 +3,8 @@ require 'ostruct'
module Rswag
module Specs
describe SwaggerFormatter do
RSpec.describe SwaggerFormatter do
subject { described_class.new(output, config) }
# Mock out some infrastructure
@ -47,7 +47,7 @@ module Rswag
end
describe '#stop' do
before do
before do
FileUtils.rm_r(swagger_root) if File.exists?(swagger_root)
allow(config).to receive(:swagger_docs).and_return(
'v1/swagger.json' => { info: { version: 'v1' } },

View File

@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"swagger-ui-dist": {
"version": "3.17.3",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.17.3.tgz",
"integrity": "sha1-37lkCMzEZ3UVX3NpGQxdSyAW/lw="
"version": "3.18.2",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.18.2.tgz",
"integrity": "sha512-pWAEiKkgWUJvjmLW9AojudnutJ+NTn5g6OdNLj1iIJWwCkoy40K3Upwa24DqFbmIE4vLX4XplND61hp2L+s5vg=="
}
}
}

View File

@ -3,6 +3,6 @@
"version": "1.0.0",
"private": true,
"dependencies": {
"swagger-ui-dist": "3.17.3"
"swagger-ui-dist": "3.18.2"
}
}

View File

@ -0,0 +1,2 @@
//= link_tree ../images
//= link_directory ../stylesheets .css

View File

View File

@ -2,15 +2,15 @@
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# This file is the source Rails uses to define your schema when running `rails
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the 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).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2016_02_18_212104) do
ActiveRecord::Schema.define(version: 20160218212104) do
create_table "blogs", force: :cascade do |t|
t.string "title"

View File

@ -1,6 +1,6 @@
require 'rails_helper'
feature 'swagger-ui', js: true do
RSpec.feature 'swagger-ui', js: true do
scenario 'browsing api-docs' do
visit '/api-docs'

View File

@ -1,6 +1,6 @@
require 'swagger_helper'
describe 'Auth Tests API', type: :request, swagger_doc: 'v1/swagger.json' do
RSpec.describe 'Auth Tests API', type: :request, swagger_doc: 'v1/swagger.json' do
path '/auth-tests/basic' do
post 'Authenticates with basic auth' do

View File

@ -1,6 +1,6 @@
require 'swagger_helper'
describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
RSpec.describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
let(:api_key) { 'fake_key' }
path '/blogs' do

View File

@ -1,9 +1,9 @@
require 'spec_helper'
require 'rake'
describe 'rswag:specs:swaggerize' do
RSpec.describe 'rswag:specs:swaggerize' do
let(:swagger_root) { Rails.root.to_s + '/swagger' }
before do
before do
TestApp::Application.load_tasks
FileUtils.rm_r(swagger_root) if File.exists?(swagger_root)
end