From 4a712d4a165ddf8c9e083e7213ad5f9d5e948c05 Mon Sep 17 00:00:00 2001 From: Jacob Harris Date: Thu, 7 Jul 2016 12:27:47 -0400 Subject: [PATCH 1/2] SwaggerChecker falls back to a local load --- lib/apivore/swagger_checker.rb | 25 +++++++++++++++++++++---- spec/swagger_checker_spec.rb | 25 +++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 spec/swagger_checker_spec.rb diff --git a/lib/apivore/swagger_checker.rb b/lib/apivore/swagger_checker.rb index aee87f1..7e08232 100644 --- a/lib/apivore/swagger_checker.rb +++ b/lib/apivore/swagger_checker.rb @@ -72,12 +72,29 @@ def load_swagger_doc! def fetch_swagger! session = ActionDispatch::Integration::Session.new(Rails.application) + body = nil + http_error = true + begin - session.get(swagger_path) - rescue - fail "Unable to perform GET request for swagger json: #{swagger_path} - #{$!}." + response_code = session.get(swagger_path) + + if response_code == 200 + http_error = false + body = session.response.body + end + rescue URI::InvalidURIError + # http_error is true end - JSON.parse(session.response.body) + + if http_error + begin + open(swagger_path) {|file| body = file.read } + rescue Errno::ENOENT + fail "Unable to perform GET request for swagger json: #{swagger_path} - #{$!}." + end + end + + JSON.parse(body) end def validate_swagger! diff --git a/spec/swagger_checker_spec.rb b/spec/swagger_checker_spec.rb new file mode 100644 index 0000000..5b70a8d --- /dev/null +++ b/spec/swagger_checker_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe Apivore::SwaggerChecker do + describe '#instance_of' do + let(:sample_file_path) { File.join(File.dirname(__FILE__), 'data', '01_sample2.0.json') } + + it 'should be able to load the file via ActionDispatch::Integration' do + json = nil + open(sample_file_path) { |file| json = file.read } + response_double = double('response', body: json) + session_double = double('integration', response: response_double, get: 200) + allow(ActionDispatch::Integration::Session).to receive(:new).and_return(session_double) + + expect { Apivore::SwaggerChecker.instance_for("/random/url.json") }.to_not raise_error + end + + it 'should be able to load the swagger file locally' do + expect { Apivore::SwaggerChecker.instance_for(sample_file_path) }.to_not raise_error + end + + it 'should throw an exception if it is unable to load the file' do + expect { Apivore::SwaggerChecker.instance_for('not_found.json') }.to raise_error(RuntimeError) + end + end +end From c2fb2860008f7369a838a58e3729520eda7c320b Mon Sep 17 00:00:00 2001 From: Phil Sturgeon Date: Mon, 20 Nov 2017 16:05:27 -0500 Subject: [PATCH 2/2] Primative YAML support It's nothing flashy, and I really don't like detecting based on end-of-filename regex, but... its better than nothing! --- lib/apivore/swagger_checker.rb | 38 ++++++++-------- spec/apivore_spec.rb | 68 ++++++++++++++++------------- spec/data/01a_sample2.0.yaml | 79 ++++++++++++++++++++++++++++++++++ spec/swagger_checker_spec.rb | 31 +++++++------ 4 files changed, 152 insertions(+), 64 deletions(-) create mode 100644 spec/data/01a_sample2.0.yaml diff --git a/lib/apivore/swagger_checker.rb b/lib/apivore/swagger_checker.rb index 7e08232..52f17ed 100644 --- a/lib/apivore/swagger_checker.rb +++ b/lib/apivore/swagger_checker.rb @@ -71,30 +71,28 @@ def load_swagger_doc! end def fetch_swagger! - session = ActionDispatch::Integration::Session.new(Rails.application) - body = nil - http_error = true - - begin - response_code = session.get(swagger_path) + body = (attempt_fetch_from_url || attempt_fetch_from_path) - if response_code == 200 - http_error = false - body = session.response.body - end - rescue URI::InvalidURIError - # http_error is true + unless body + fail "Unable to load URL or file: #{swagger_path}." end - if http_error - begin - open(swagger_path) {|file| body = file.read } - rescue Errno::ENOENT - fail "Unable to perform GET request for swagger json: #{swagger_path} - #{$!}." - end - end + # Check if its JSON or YAML + (swagger_path =~ /.json$/) ? JSON.parse(body) : YAML.load(body) + end + + def attempt_fetch_from_url + session = ActionDispatch::Integration::Session.new(Rails.application) + response_code = session.get(swagger_path) + session.response.body if response_code == 200 + rescue URI::InvalidURIError + nil + end - JSON.parse(body) + def attempt_fetch_from_path + File.read(swagger_path) + rescue Errno::ENOENT + nil end def validate_swagger! diff --git a/spec/apivore_spec.rb b/spec/apivore_spec.rb index 95cb649..3b2f372 100644 --- a/spec/apivore_spec.rb +++ b/spec/apivore_spec.rb @@ -3,36 +3,44 @@ describe 'Apivore::Swagger' do context 'with valid swagger 2.0 input' do - let(:doc) { IO.read(File.join(File.dirname(__FILE__), "data", "01_sample2.0.json")) } - let(:swagger) { Apivore::Swagger.new(JSON.parse(doc)) } - - subject { swagger } - it { should be_an_instance_of(Apivore::Swagger) } - it { should respond_to(:version) } - it { should respond_to(:validate) } - it { should respond_to(:each_response) } - it { should respond_to(:base_path) } - - describe 'swagger version' do - subject { swagger.version } - it { should == '2.0' } - end - - describe 'Swagger 2.0 validation issues' do - subject { swagger.validate } - it { should be_empty } - end - - describe 'each_response' do - it "should return the responses" do - expect { |b| swagger.each_response(&b) }.to yield_successive_args( - ["/services.json", "get", "200", ['#', 'paths', '/services.json', 'get', 'responses', '200', 'schema']], - ["/services.json", "post", "204", nil], - ["/services/{id}.json", "get", "200", ['#', 'paths', '/services/{id}.json', 'get', 'responses', '200', 'schema']], - ["/services/{id}.json", "put", "204", nil], - ["/services/{id}.json", "delete", "204", nil], - ["/services/{id}.json", "patch", "204", nil] - ) + ['01_sample2.0.json', '01a_sample2.0.yaml'].each do |file| + + context "input file #{file}" do + let(:doc) { IO.read(File.join(File.dirname(__FILE__), "data", file)) } + let(:swagger) do + contents = (file =~ /.json$/) ? JSON.parse(doc) : YAML.load(doc) + Apivore::Swagger.new(contents) + end + + subject { swagger } + it { should be_an_instance_of(Apivore::Swagger) } + it { should respond_to(:version) } + it { should respond_to(:validate) } + it { should respond_to(:each_response) } + it { should respond_to(:base_path) } + + describe 'swagger version' do + subject { swagger.version } + it { should == '2.0' } + end + + describe 'Swagger 2.0 validation issues' do + subject { swagger.validate } + it { should be_empty } + end + + describe 'each_response' do + it "should return the responses" do + expect { |b| swagger.each_response(&b) }.to yield_successive_args( + ["/services.json", "get", "200", ['#', 'paths', '/services.json', 'get', 'responses', '200', 'schema']], + ["/services.json", "post", "204", nil], + ["/services/{id}.json", "get", "200", ['#', 'paths', '/services/{id}.json', 'get', 'responses', '200', 'schema']], + ["/services/{id}.json", "put", "204", nil], + ["/services/{id}.json", "delete", "204", nil], + ["/services/{id}.json", "patch", "204", nil] + ) + end + end end end end diff --git a/spec/data/01a_sample2.0.yaml b/spec/data/01a_sample2.0.yaml new file mode 100644 index 0000000..3c7c6ff --- /dev/null +++ b/spec/data/01a_sample2.0.yaml @@ -0,0 +1,79 @@ +swagger: '2.0' +info: + version: testing + title: Example Centre Directory Service +host: api.test.example.com +basePath: "/api" +schemes: +- https +consumes: +- application/json +produces: +- application/json +paths: + x-something: Vendor Specific Tag + "/services.json": + x-something: Vendor Specific Tag + get: + description: Services available to shoppers. + operationId: Services#index + responses: + '200': + description: service index response + schema: + type: array + items: + "$ref": "#/definitions/service" + post: + description: Creates a service. + operationId: Services#post + responses: + '204': + description: Service created + "/services/{id}.json": + parameters: + - name: id + in: path + description: Service identifier. + required: true + type: integer + get: + description: Returns a service. + operationId: Services#show + responses: + '200': + description: show service response + schema: + "$ref": "#/definitions/service" + put: + description: Update a service. + operationId: Services#put + responses: + '204': + description: Service updated + delete: + description: Deletes a service. + operationId: Services#delete + responses: + '204': + description: Service deleted + patch: + description: Patches a service. + operationId: Services#patch + responses: + '204': + description: Service patched +definitions: + service: + type: object + required: + - id + properties: + id: + type: integer + description: Service id + name: + type: + - string + - 'null' + description: Service name diff --git a/spec/swagger_checker_spec.rb b/spec/swagger_checker_spec.rb index 5b70a8d..6831213 100644 --- a/spec/swagger_checker_spec.rb +++ b/spec/swagger_checker_spec.rb @@ -2,24 +2,27 @@ describe Apivore::SwaggerChecker do describe '#instance_of' do - let(:sample_file_path) { File.join(File.dirname(__FILE__), 'data', '01_sample2.0.json') } + ['01_sample2.0.json', '01a_sample2.0.yaml'].each do |file| - it 'should be able to load the file via ActionDispatch::Integration' do - json = nil - open(sample_file_path) { |file| json = file.read } - response_double = double('response', body: json) - session_double = double('integration', response: response_double, get: 200) - allow(ActionDispatch::Integration::Session).to receive(:new).and_return(session_double) + context "input file #{file}" do + let(:sample_file_path) { File.join(File.dirname(__FILE__), "data", file) } - expect { Apivore::SwaggerChecker.instance_for("/random/url.json") }.to_not raise_error - end + it 'should be able to load the file via ActionDispatch::Integration' do + response_double = double('response', body: IO.read(sample_file_path)) + session_double = double('integration', response: response_double, get: 200) + allow(ActionDispatch::Integration::Session).to receive(:new).and_return(session_double) - it 'should be able to load the swagger file locally' do - expect { Apivore::SwaggerChecker.instance_for(sample_file_path) }.to_not raise_error - end + expect { Apivore::SwaggerChecker.instance_for("/random/#{file}") }.to_not raise_error + end + + it 'should be able to load the swagger file locally' do + expect { Apivore::SwaggerChecker.instance_for(sample_file_path) }.to_not raise_error + end - it 'should throw an exception if it is unable to load the file' do - expect { Apivore::SwaggerChecker.instance_for('not_found.json') }.to raise_error(RuntimeError) + it 'should throw an exception if it is unable to load the file' do + expect { Apivore::SwaggerChecker.instance_for('not_found.json') }.to raise_error(RuntimeError) + end + end end end end