Skip to content

Commit

Permalink
Merge pull request #54 from hornc/custom_schemata
Browse files Browse the repository at this point in the history
[CNTR-746] Allow swagger validation against custom schemata
  • Loading branch information
hornc committed Jul 7, 2015
2 parents 79bb131 + 7f1a570 commit 0ba4ded
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 3 deletions.
5 changes: 3 additions & 2 deletions apivore.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ $:.push File.expand_path("../lib", __FILE__)

Gem::Specification.new do |s|
s.name = 'apivore'
s.version = '1.2.0'
s.date = '2015-05-20'
s.version = '1.3.0'
s.date = '2015-06-11'
s.summary = "Tests your API against its Swagger 2.0 spec"
s.description = "Tests your rails API using its Swagger description of end-points, models, and query parameters."
s.authors = ["Charles Horn"]
s.email = '[email protected]'
s.files = ['lib/apivore.rb', 'data/swagger_2.0_schema.json', 'data/draft04_schema.json']
s.files += Dir['lib/apivore/*.rb']
s.files += Dir['data/custom_schemata/*.json']
s.homepage = 'http://github.com/westfieldlabs/apivore'
s.licenses = ['Apache 2.0', 'MIT']

Expand Down
26 changes: 26 additions & 0 deletions data/custom_schemata/westfield_api_standards.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"title": "Westfield API Standards",

"type": "object",
"properties": {
"definitions": {
"description": "All entities defined in the 'definitions' section must include an explicit 'type: object' attribute. This forces the entity to be validated.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/schemaObject"
}
}
},
"definitions": {
"schemaObject": {
"type": "object",
"required": [ "type" ],
"properties": {
"type": {
"type": "string",
"enum": [ "object" ]
}
}
}
}
}
20 changes: 20 additions & 0 deletions lib/apivore/custom_schema_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Apivore
class CustomSchemaValidator
def initialize(custom_schema)
@schema = File.expand_path("../../data/custom_schemata/#{custom_schema}", File.dirname(__FILE__))
end

def matches?(swagger_checker)
@results = JSON::Validator.fully_validate(@schema, swagger_checker.swagger)
@results.empty?
end

def description
"additionally conforms to #{@schema}"
end

def failure_message
@results.join("\n")
end
end
end
5 changes: 5 additions & 0 deletions lib/apivore/rspec_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
require 'apivore/validator'
require 'apivore/all_routes_tested_validator'
require 'apivore/custom_schema_validator'

module Apivore
module RspecHelpers
def validate(method, path, response_code, params = {})
Validator.new(method, path, response_code, params)
end

def conform_to(custom_schema)
CustomSchemaValidator.new(custom_schema)
end

def validate_all_paths
AllRoutesTestedValidator.new
end
Expand Down
103 changes: 103 additions & 0 deletions spec/data/08_untyped_definition.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"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": {
"/services.json": {
"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": {
"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": {

"required": [ "id" ],
"properties": {
"id": {
"type": "integer",
"description": "Service id"
},
"name": {
"type": ["string", "null"],
"description": "Service name"
}
}
}
}
}
11 changes: 11 additions & 0 deletions spec/data/example_specs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,15 @@
expect(subject).to validate(:get, "/services/{id}.json", 200, { "id" => 1})
end
end

describe "fails custom validation" do
subject { Apivore::SwaggerChecker.instance_for("/08_untyped_definition.json") }
it "passes" do
expect(subject).to validate(:get, "/services.json", 200)
end

it "fails" do
expect(subject).to conform_to("westfield_api_standards.json")
end
end
end
1 change: 1 addition & 0 deletions spec/fixtures/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def call(env)
"/05_extra_properties.json",
"/06_missing_required_property.json",
"/07_missing_non-required_property.json",
"/08_untyped_definition.json",
]
case "#{method} #{path}"
when "GET /swagger-doc.json"
Expand Down
8 changes: 8 additions & 0 deletions spec/integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,12 @@
expect(stdout).to match(/0 failures/)
end
end

describe "a swagger document not conforming to a custom schema" do
it 'should fail the additional validation' do
stdout = `rspec spec/data/example_specs.rb --example 'fails custom validation'`
expect(stdout).to match(/1 failure/)
expect(stdout).to include("The property '#/definitions/service' did not contain a required property of 'type'")
end
end
end
6 changes: 5 additions & 1 deletion spec/request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,13 @@
end

context 'and' do
it 'tests all documented routes' do
it 'has had all documented routes tested' do
expect(subject).to validate_all_paths
end

it 'additionally conforms to a custom schema' do
expect(subject).to conform_to("westfield_api_standards.json")
end
# it 'has definitions consistent with the master docs' do
# expect(subject).to be_consistent_with_swagger_definitions(
# "api.westfield.io", 'deal'
Expand Down

0 comments on commit 0ba4ded

Please sign in to comment.