mirror of
https://github.com/ditkrg/rswag.git
synced 2026-01-23 06:16:42 +00:00
Honor basePath, output tags & other cleanup
This commit is contained in:
parent
452917e0d9
commit
9a327e84cf
@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
swagger_rails (0.0.1)
|
||||
swagger_rails (1.0.0.pre.beta)
|
||||
rails (>= 3.1, < 5)
|
||||
|
||||
GEM
|
||||
@ -111,7 +111,7 @@ GEM
|
||||
treetop (1.4.15)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.46)
|
||||
tzinfo (0.3.49)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@ -119,6 +119,9 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
generator_spec
|
||||
pry
|
||||
rspec-rails
|
||||
rspec-rails (~> 3.0)
|
||||
sqlite3
|
||||
swagger_rails!
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.6
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
swagger_rails
|
||||
=========
|
||||
|
||||
Leverage your api/integration test specs to generate [swagger](http://swagger.io/) descriptions for Rails-based API's. Use the provided DSL to accurately test and describe API operations in your spec files. Then, you can easily generate corresponding swagger.json files and serve them up with an embedded version of [swagger-ui](https://github.com/swagger-api/swagger-ui). This means you can complement your API with a slick discovery UI to assist consumers with their integration efforts. Best of all, it requires minimal coding and maintenance, allowing you to focus on building an awesome API!
|
||||
Generate API documentation, including a slick discovery UI and playground, directly from your rspec integration specs. Use the provided DSL to describe and test API operations in your spec files. Then, you can easily generate corresponding swagger.json files and serve them up with an embedded version of [swagger-ui](https://github.com/swagger-api/swagger-ui). Best of all, it requires minimal coding and maintenance, allowing you to focus on building an awesome API!
|
||||
|
||||
And that's not all ...
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ module SwaggerRails
|
||||
|
||||
def index
|
||||
@discovery_paths = Hash[
|
||||
SwaggerRails.swagger_docs.map do |path, doc|
|
||||
SwaggerRails.config.swagger_docs.map do |path, doc|
|
||||
[ "#{root_path}#{path}", doc[:info][:title] ]
|
||||
end
|
||||
]
|
||||
|
||||
@ -6,7 +6,7 @@ module SwaggerRails
|
||||
source_root File.expand_path('../templates', __FILE__)
|
||||
|
||||
def add_swagger_dir
|
||||
empty_directory('config/swagger/v1')
|
||||
empty_directory('swagger/v1')
|
||||
end
|
||||
|
||||
def add_initializer
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"version": "0.0.0",
|
||||
"title": "[Enter a description for your API here]",
|
||||
"description": "The docs below are powered by the default swagger.json that gets installed with swagger_rails. You'll need to update it to describe your API. See here for the complete swagger spec - https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md"
|
||||
},
|
||||
"paths": {
|
||||
"/a/sample/resource": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"a/sample/resource"
|
||||
],
|
||||
"description": "Create a new sample resource",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/CreateSampleResource"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Ok"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"CreateSampleResource": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"date_time": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,16 @@
|
||||
SwaggerRails.configure do |c|
|
||||
|
||||
# Define your swagger documents and provide global metadata
|
||||
# Describe actual operations in your spec/test files
|
||||
c.swagger_doc 'v1/swagger.json' do
|
||||
# Define your swagger documents and provide any global metadata here
|
||||
# (Individual operations are generated from your spec/test files)
|
||||
c.swagger_doc 'v1/swagger.json',
|
||||
{
|
||||
swagger: '2.0',
|
||||
info: {
|
||||
title: 'API V1',
|
||||
version: 'v1'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# Specify a location to output generated swagger files
|
||||
c.swagger_dir File.expand_path('../../../swagger', __FILE__)
|
||||
end
|
||||
|
||||
@ -2,23 +2,32 @@ require "swagger_rails/engine"
|
||||
|
||||
module SwaggerRails
|
||||
|
||||
def self.configure
|
||||
yield self
|
||||
class Configuration
|
||||
attr_reader :swagger_docs, :swagger_dir_string
|
||||
|
||||
def initialize
|
||||
@swagger_docs = {}
|
||||
@swagger_dir_string = nil
|
||||
end
|
||||
|
||||
def swagger_doc(path, doc)
|
||||
@swagger_docs[path] = doc
|
||||
end
|
||||
|
||||
def swagger_dir(dir_string)
|
||||
@swagger_dir_string = dir_string
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
@@swagger_docs = {}
|
||||
attr_reader :config
|
||||
|
||||
def swagger_doc(path, &block)
|
||||
@@swagger_docs[path] = block
|
||||
def configure
|
||||
yield config
|
||||
end
|
||||
|
||||
def swagger_docs
|
||||
Hash[
|
||||
@@swagger_docs.map do |path, factory|
|
||||
[ path, factory.call.merge(swagger: '2.0') ]
|
||||
end
|
||||
]
|
||||
def config
|
||||
@config ||= Configuration.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -6,7 +6,7 @@ module SwaggerRails
|
||||
isolate_namespace SwaggerRails
|
||||
|
||||
initializer 'swagger_rails.initialize' do |app|
|
||||
middleware.use SwaggerDocs, File.join(app.root, 'config', 'swagger')
|
||||
middleware.use SwaggerDocs, SwaggerRails.config.swagger_dir_string
|
||||
middleware.use SwaggerUi, "#{root}/bower_components/swagger-ui/dist"
|
||||
end
|
||||
end
|
||||
|
||||
@ -49,12 +49,20 @@ module SwaggerRails
|
||||
end
|
||||
|
||||
def run_test!
|
||||
if metadata.has_key?(:swagger_doc)
|
||||
swagger_doc = SwaggerRails.config.swagger_docs[metadata[:swagger_doc]]
|
||||
else
|
||||
swagger_doc = SwaggerRails.config.swagger_docs.values.first
|
||||
end
|
||||
|
||||
test_visitor = SwaggerRails::TestVisitor.new(swagger_doc)
|
||||
|
||||
before do |example|
|
||||
SwaggerRails::TestVisitor.instance.submit_request!(self, example.metadata)
|
||||
test_visitor.submit_request!(self, example.metadata)
|
||||
end
|
||||
|
||||
it "returns a #{metadata[:response_code]} status" do |example|
|
||||
SwaggerRails::TestVisitor.instance.assert_response!(self, example.metadata)
|
||||
test_visitor.assert_response!(self, example.metadata)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -9,9 +9,10 @@ module SwaggerRails
|
||||
:example_group_finished,
|
||||
:stop
|
||||
|
||||
def initialize(output)
|
||||
def initialize(output, config=SwaggerRails.config)
|
||||
@output = output
|
||||
@swagger_docs = SwaggerRails.swagger_docs
|
||||
@swagger_docs = config.swagger_docs
|
||||
@swagger_dir_string = config.swagger_dir_string
|
||||
|
||||
@output.puts 'Generating Swagger Docs ...'
|
||||
end
|
||||
@ -20,14 +21,14 @@ module SwaggerRails
|
||||
metadata = notification.group.metadata
|
||||
return unless metadata.has_key?(:response_code)
|
||||
|
||||
swagger_doc = @swagger_docs[metadata[:swagger_doc]] || @swagger_docs.values.first
|
||||
swagger_data = swagger_data_from(metadata)
|
||||
swagger_doc = @swagger_docs[metadata[:docs_path]] || @swagger_docs.values.first
|
||||
swagger_doc.deep_merge!(swagger_data)
|
||||
end
|
||||
|
||||
def stop(notification)
|
||||
@swagger_docs.each do |path, doc|
|
||||
file_path = File.join(Rails.root, 'config/swagger', path)
|
||||
file_path = File.join(@swagger_dir_string, path)
|
||||
|
||||
File.open(file_path, 'w') do |file|
|
||||
file.write(JSON.pretty_generate(doc))
|
||||
@ -50,11 +51,19 @@ module SwaggerRails
|
||||
end
|
||||
|
||||
def operation_from(metadata)
|
||||
metadata.slice(:summary, :consumes, :produces, :parameters).tap do |operation|
|
||||
operation[:responses] = {
|
||||
metadata[:response_code] => metadata[:response]
|
||||
}
|
||||
end
|
||||
{
|
||||
tags: [ find_root_of(metadata)[:description] ] ,
|
||||
summary: metadata[:summary],
|
||||
consumes: metadata[:consumes],
|
||||
produces: metadata[:produces],
|
||||
parameters: metadata[:parameters],
|
||||
responses: { metadata[:response_code] => metadata[:response] }
|
||||
}
|
||||
end
|
||||
|
||||
def find_root_of(metadata)
|
||||
parent = metadata[:parent_example_group]
|
||||
parent.nil? ? metadata : find_root_of(parent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
require 'singleton'
|
||||
|
||||
module SwaggerRails
|
||||
class TestVisitor
|
||||
include Singleton
|
||||
|
||||
def initialize(swagger_doc)
|
||||
@swagger_doc = swagger_doc
|
||||
end
|
||||
|
||||
def submit_request!(test, metadata)
|
||||
params_data = params_data_for(test, metadata[:parameters])
|
||||
@ -35,6 +36,7 @@ module SwaggerRails
|
||||
path_params_data.each do |param_data|
|
||||
path.sub!("\{#{param_data[:name]}\}", param_data[:value].to_s)
|
||||
end
|
||||
path.prepend(@swagger_doc[:basePath] || '')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -4,9 +4,10 @@
|
||||
# end
|
||||
|
||||
require 'rspec/core/rake_task'
|
||||
require 'swagger_rails'
|
||||
|
||||
desc 'Generate Swagger JSON files from integration specs'
|
||||
RSpec::Core::RakeTask.new('swaggerize') do |t|
|
||||
t.pattern = 'spec/integration/**/*_spec.rb'
|
||||
t.pattern = 'spec/requests/**/*_spec.rb, spec/api/**/*_spec.rb, spec/integration/**/*_spec.rb'
|
||||
t.rspec_opts = [ '--format SwaggerRails::RSpec::Formatter', '--dry-run' ]
|
||||
end
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
SwaggerRails.configure do |c|
|
||||
|
||||
# Define your swagger documents and provide global metadata
|
||||
# Describe actual operations in your spec/test files
|
||||
c.swagger_doc 'v1/swagger.json' do
|
||||
# Define your swagger documents and provide any global metadata here
|
||||
# (Individual operations are generated from your spec/test files)
|
||||
c.swagger_doc 'v1/swagger.json',
|
||||
{
|
||||
swagger: '2.0',
|
||||
info: {
|
||||
title: 'API V1',
|
||||
version: 'v1'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# Specify a location to output generated swagger files
|
||||
c.swagger_dir File.expand_path('../../../swagger', __FILE__)
|
||||
end
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
Rails.application.routes.draw do
|
||||
resources :blogs, defaults: { :format => :json }
|
||||
|
||||
mount SwaggerRails::Engine => '/api-docs'
|
||||
|
||||
resources :blogs, defaults: { :format => :json }
|
||||
end
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe 'Blogs API', swagger_doc: 'blogs/v1/swagger.json' do
|
||||
describe 'Blogs API', swagger_doc: 'v1/swagger.json' do
|
||||
|
||||
path '/blogs' do
|
||||
|
||||
|
||||
90
spec/dummy/swagger/v1/swagger.json
Normal file
90
spec/dummy/swagger/v1/swagger.json
Normal file
@ -0,0 +1,90 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "API V1",
|
||||
"version": "v1"
|
||||
},
|
||||
"paths": {
|
||||
"/blogs": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Blogs API"
|
||||
],
|
||||
"summary": "creates a new blog",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "blog",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "valid request"
|
||||
},
|
||||
"422": {
|
||||
"description": "invalid request"
|
||||
}
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"tags": [
|
||||
"Blogs API"
|
||||
],
|
||||
"summary": "searches existing blogs",
|
||||
"consumes": null,
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "valid request"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/blogs/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Blogs API"
|
||||
],
|
||||
"summary": "retreives a specific blog",
|
||||
"consumes": null,
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "blog found"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,7 @@ describe SwaggerRails::InstallGenerator do
|
||||
end
|
||||
|
||||
it 'creates a default swagger directory' do
|
||||
assert_directory('config/swagger/v1')
|
||||
assert_directory('swagger/v1')
|
||||
end
|
||||
|
||||
it 'creates a swagger_rails initializer' do
|
||||
|
||||
@ -5,7 +5,8 @@ module SwaggerRails
|
||||
|
||||
describe TestVisitor do
|
||||
let(:test) { spy('test') }
|
||||
subject { described_class.instance }
|
||||
let(:swagger_doc) { {} }
|
||||
subject { described_class.new(swagger_doc) }
|
||||
|
||||
describe '#submit_request!' do
|
||||
before { subject.submit_request!(test, metadata) }
|
||||
@ -93,6 +94,21 @@ module SwaggerRails
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a basePath is provided' do
|
||||
let(:swagger_doc) { { basePath: '/api' } }
|
||||
let(:metadata) do
|
||||
{
|
||||
path_template: '/resource',
|
||||
http_verb: :get,
|
||||
parameters: []
|
||||
}
|
||||
end
|
||||
|
||||
it 'prepends the basePath to the request path' do
|
||||
expect(test).to have_received(:get).with('/api/resource', {}, {})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#assert_response' do
|
||||
|
||||
Loading…
Reference in New Issue
Block a user