diff --git a/lib/apivore/swagger_checker.rb b/lib/apivore/swagger_checker.rb index aee87f1..52f17ed 100644 --- a/lib/apivore/swagger_checker.rb +++ b/lib/apivore/swagger_checker.rb @@ -71,13 +71,28 @@ def load_swagger_doc! end def fetch_swagger! - session = ActionDispatch::Integration::Session.new(Rails.application) - begin - session.get(swagger_path) - rescue - fail "Unable to perform GET request for swagger json: #{swagger_path} - #{$!}." + body = (attempt_fetch_from_url || attempt_fetch_from_path) + + unless body + fail "Unable to load URL or file: #{swagger_path}." end - JSON.parse(session.response.body) + + # 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 + + 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 new file mode 100644 index 0000000..6831213 --- /dev/null +++ b/spec/swagger_checker_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe Apivore::SwaggerChecker do + describe '#instance_of' do + ['01_sample2.0.json', '01a_sample2.0.yaml'].each do |file| + + context "input file #{file}" do + let(:sample_file_path) { File.join(File.dirname(__FILE__), "data", file) } + + 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) + + 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) + end + end + end + end +end