Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardize on swagger_doc naming #45

Merged
merged 2 commits into from
Apr 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 44 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ rails generate rspec:swagger_install
## Documenting Your API

Now you can edit `spec/swagger_helper.rb` and start filling in the top level
Swagger documention, e.g. basePath, [definitions](http://swagger.io/specification/#definitionsObject),
Swagger documentation, e.g. basePath, [definitions](http://swagger.io/specification/#definitionsObject),
[parameters](http://swagger.io/specification/#parametersDefinitionsObject),
[tags](http://swagger.io/specification/#tagObject), etc.

Expand Down Expand Up @@ -66,7 +66,7 @@ works pretty well and supports multiple documents.

## RSpec DSL

The DSL follows the hierachy of the Swagger Schema:
The DSL follows the hierarchy of the Swagger Schema:

- [Paths Object](http://swagger.io/specification/#paths-object-29)
- [Path Item Object](http://swagger.io/specification/#path-item-object-32)
Expand Down Expand Up @@ -98,7 +98,7 @@ RSpec.describe "Posts Controller", type: :request do
# Path Object
path '/posts/{post_id}' do
# Parameter Object
parameter "post_id", {in: :path, type: :integer}
parameter "post_id", { in: :path, type: :integer }
let(:post_id) { 1 }

# Operation Object
Expand All @@ -113,30 +113,30 @@ RSpec.describe "Posts Controller", type: :request do
# Parameter Object for content type could be defined like:
consumes 'application/json'
# or:
parameter 'Content-Type', {in: :header, type: :string}
parameter 'Content-Type', { in: :header, type: :string }
let(:'Content-Type') { 'application/json' }
# one of them would be considered

# authorization token in the header:
parameter 'Authorization', {in: :header, type: :string}
parameter 'Authorization', { in: :header, type: :string }
let(:'Authorization') { 'Bearer <token-here>' }

# Parameter Object
parameter "post_id", {in: :path, type: :integer}
parameter "post_id", { in: :path, type: :integer }
let(:post_id) { 1 }

# Parameter Object for Body
parameter "body", {in: :body, required: true, schema: {
parameter "body", { in: :body, required: true, schema: {
type: :object,
properties: {
title: { type: :string },
author_email: { type: :email }
}
}
let (:body) {
{ post:
{ title: 'my example',
author_email: 'me@example.com' }
{ post:
{ title: 'my example',
author_email: 'me@example.com' }
}
}
}
Expand All @@ -158,12 +158,44 @@ These methods are available inside of an RSpec contexts with the `type: :request
#### `path(template, attributes = {}, &block)`
Defines a new Path Item.

The `attributes` parameter accepts:
- `swagger_doc` a key in `RSpec.configuration.swagger_docs` that determines
which file the path belongs in.
- `tags` with an array of tags that will be applied to the child Operations.

You can also provide a default file and tags by setting them on a parent RSpec
context block:
```rb
RSpec.describe "Sample Requests", type: :request do
# The swagger_doc will be used as a default for the paths defined within the
# context block. Similarly, the tags will be merged with those set on paths
# defined within them.
context "setting defaults", swagger_doc: 'default_document.json', tags: [:context_tag] do
path '/posts', swagger_doc: 'overridden_document.yaml' tags: ['path_tag'] do
operation "GET", summary: "fetch list" do
produces 'application/json'
tags 'operation_tag'

response(200, { description: "successful" })
end
end
end
end
```
The `GET /posts` operation in this example will be saved in the `'overridden_document.yaml'`
file and tagged with `["context_tag", "path_tag", "operation_tag"]`.


### Path Item Object
These methods are available inside of blocks passed to the `path` method.

#### `operation(method, attributes = {}, &block)`
Defines a new Operation Object. The `method` is case insensitive.

The `attributes` parameter accepts:
- `tags` with an array of tags. These will be merged with tags passed to the
Path Item or `tags` method inside the Operation's block.

#### `delete(attributes = {}, &block)`
Alias for `operation(:delete, attributes, block)`.

Expand Down Expand Up @@ -203,7 +235,7 @@ parameter ref: "#/parameters/site_id"
Values for the parameters are set using `let`:
```rb
post summary: "create" do
parameter "body", in: :body, schema: { foo: :bar}
parameter "body", in: :body, schema: { foo: :bar }
let(:body) { { post: { title: 'asdf', body: "blah" } } }
# ...
end
Expand Down Expand Up @@ -245,7 +277,7 @@ RSpec.describe "Sample Requests", type: :request, tags: [:context_tag] do
produces 'application/json'
tags 'operation_tag'

response(200, {description: "successful"})
response(200, { description: "successful" })
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rspec/rails/swagger/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def example_finished(notification)
return unless metadata[:swagger_object] == :response

# Then add everything to the document
document = document_for(metadata[:swagger_document])
document = document_for(metadata[:swagger_doc])
path_item = path_item_for(document, metadata[:swagger_path_item])
operation = operation_for(path_item, metadata[:swagger_operation])
response = response_for(operation, metadata[:swagger_response])
Expand Down
10 changes: 8 additions & 2 deletions lib/rspec/rails/swagger/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def path template, attributes = {}, &block
#TODO template might be a $ref
meta = {
swagger_object: :path_item,
swagger_document: attributes[:swagger_document] || RSpec.configuration.swagger_docs.keys.first,
swagger_doc: attributes[:swagger_doc] || default_document,
swagger_path_item: {path: template},
}
# Merge tags passed into the path with those from parent contexts.
Expand All @@ -54,6 +54,12 @@ def path template, attributes = {}, &block
end
describe(template, meta, &block)
end

private

def default_document
metadata.try(:[], :swagger_doc) || RSpec.configuration.swagger_docs.keys.first
end
end

module PathItem
Expand Down Expand Up @@ -122,7 +128,7 @@ def parameter name, attributes = {}
def resolve_document metadata
# TODO: It's really inefficient to keep recreating this. It'd be nice
# if we could cache them some place.
name = metadata[:swagger_document]
name = metadata[:swagger_doc]
Document.new(RSpec.configuration.swagger_docs[name])
end

Expand Down
3 changes: 1 addition & 2 deletions lib/rspec/rails/swagger/request_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ def initialize(metadata, instance)
# and parameter references can be resolved.
def document
@document ||= begin
name = metadata[:swagger_document]
Document.new(RSpec.configuration.swagger_docs[name])
Document.new(RSpec.configuration.swagger_docs[metadata[:swagger_doc]])
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/rspec/rails/swagger/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Rails
# Version information for RSpec Swagger.
module Swagger
module Version
STRING = '0.1.5'
STRING = '0.2.0'
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/rspec/rails/swagger/formatter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def minimal
let(:metadata) do
{
swagger_object: :response,
swagger_document: 'doc2.json',
swagger_doc: 'doc2.json',
swagger_path_item: {path: "/ping"},
swagger_operation: {method: :put},
swagger_response: {status_code: 200, description: "OK"},
Expand Down
76 changes: 76 additions & 0 deletions spec/rspec/rails/swagger/helpers_paths_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
require 'swagger_helper'

RSpec.describe RSpec::Rails::Swagger::Helpers::Paths do
let(:klass) do
Class.new do
include RSpec::Rails::Swagger::Helpers::Paths
attr_accessor :metadata
def describe *args ; end
end
end
subject { klass.new }

it "requires the path start with a /" do
expect{ subject.path("foo") }.to raise_exception(ArgumentError)
expect{ subject.path("/foo") }.not_to raise_exception
end

describe 'swagger_doc' do
context 'with value specified in parent context' do
before { subject.metadata = {swagger_doc: 'default.json'} }

it "defaults to the parent value" do
expect(subject).to receive(:describe).with("/ping", {
swagger_object: :path_item,
swagger_doc: 'default.json',
swagger_path_item: {path: '/ping'}
})

subject.path('/ping')
end

it "uses the argument when provided" do
expect(subject).to receive(:describe).with("/ping", {
swagger_object: :path_item,
swagger_doc: 'overridden.json',
swagger_path_item: {path: '/ping'}
})

subject.path('/ping', swagger_doc: 'overridden.json')
end
end

context 'without a parent swagger_doc' do
it "defaults to the first swagger document" do
expect(subject).to receive(:describe).with("/ping", {
swagger_object: :path_item,
swagger_doc: RSpec.configuration.swagger_docs.keys.first,
swagger_path_item: {path: '/ping'}
})

subject.path('/ping')
end

it "uses the argument when provided" do
expect(subject).to receive(:describe).with("/ping", {
swagger_object: :path_item,
swagger_doc: 'overridden.json',
swagger_path_item: {path: '/ping'}
})

subject.path('/ping', swagger_doc: 'overridden.json')
end
end
end

it "passes tags through to the metadata" do
expect(subject).to receive(:describe).with("/ping", {
swagger_object: :path_item,
swagger_doc: RSpec.configuration.swagger_docs.keys.first,
swagger_path_item: {path: '/ping'},
tags: ['tag1']
})

subject.path('/ping', tags: ['tag1'])
end
end
47 changes: 0 additions & 47 deletions spec/rspec/rails/swagger/helpers_spec.rb
Original file line number Diff line number Diff line change
@@ -1,52 +1,5 @@
require 'swagger_helper'

RSpec.describe RSpec::Rails::Swagger::Helpers::Paths do
let(:klass) do
Class.new do
include RSpec::Rails::Swagger::Helpers::Paths
attr_accessor :metadata
def describe *args ; end
end
end
subject { klass.new }

it "requires the path start with a /" do
expect{ subject.path("foo") }.to raise_exception(ArgumentError)
expect{ subject.path("/foo") }.not_to raise_exception
end

it "defaults to the first swagger document if not specified" do
expect(subject).to receive(:describe).with("/ping", {
swagger_object: :path_item,
swagger_document: RSpec.configuration.swagger_docs.keys.first,
swagger_path_item: {path: '/ping'}
})

subject.path('/ping')
end

it "accepts specified swagger document name" do
expect(subject).to receive(:describe).with("/ping", {
swagger_object: :path_item,
swagger_document: 'hello_swagger.json',
swagger_path_item: {path: '/ping'}
})

subject.path('/ping', swagger_document: 'hello_swagger.json')
end

it "passes tags through to the metadata" do
expect(subject).to receive(:describe).with("/ping", {
swagger_object: :path_item,
swagger_document: RSpec.configuration.swagger_docs.keys.first,
swagger_path_item: {path: '/ping'},
tags: ['tag1']
})

subject.path('/ping', tags: ['tag1'])
end
end

RSpec.describe RSpec::Rails::Swagger::Helpers::PathItem do
let(:klass) do
Class.new do
Expand Down
2 changes: 1 addition & 1 deletion spec/rspec/rails/swagger/request_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

describe '#document' do
subject { described_class.new(metadata, double('instance')) }
let(:metadata) { { swagger_document: 'example.json' } }
let(:metadata) { { swagger_doc: 'example.json' } }

it 'loads the document' do
allow(RSpec.configuration.swagger_docs).to receive(:[]).with('example.json').and_return({foo: :bar})
Expand Down