skeleton 0.3.3 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +140 -65
- data/Rakefile +10 -3
- data/lib/skeleton.rb +6 -10
- data/lib/skeleton/contact.rb +1 -13
- data/lib/skeleton/error.rb +4 -0
- data/lib/skeleton/graph.rb +56 -0
- data/lib/skeleton/header.rb +2 -63
- data/lib/skeleton/items.rb +34 -0
- data/lib/skeleton/license.rb +1 -12
- data/lib/skeleton/model.rb +13 -17
- data/lib/skeleton/operation.rb +50 -121
- data/lib/skeleton/parameter.rb +31 -88
- data/lib/skeleton/parameters.rb +40 -0
- data/lib/skeleton/path.rb +42 -80
- data/lib/skeleton/presenter.rb +19 -0
- data/lib/skeleton/property.rb +6 -0
- data/lib/skeleton/response.rb +24 -45
- data/lib/skeleton/schema.rb +80 -63
- data/lib/skeleton/scope.rb +18 -0
- data/lib/skeleton/security_scheme.rb +19 -37
- data/lib/skeleton/serializers/options.rb +215 -0
- data/lib/skeleton/serializers/swagger.rb +197 -0
- data/lib/skeleton/structure.rb +92 -138
- data/lib/skeleton/swagger.rb +9 -0
- data/lib/skeleton/tag.rb +11 -16
- data/lib/skeleton/version.rb +1 -1
- data/skeleton.gemspec +2 -0
- data/test/fixtures/json-schema-draft-04.json +150 -0
- data/test/fixtures/schema.json +1482 -0
- data/test/integrations/validate_complex_schema_spec.rb +42 -0
- data/test/skeleton/graph_test.rb +22 -0
- data/test/skeleton/mapper_test.rb +84 -0
- data/test/skeleton/operation_test.rb +11 -0
- data/test/skeleton/parameter_test.rb +34 -0
- data/test/skeleton/parameters_test.rb +9 -0
- data/test/skeleton/path_test.rb +46 -0
- data/test/skeleton/property_test.rb +8 -0
- data/test/skeleton/serializers/options_test.rb +68 -0
- data/test/skeleton/serializers/swagger_test.rb +30 -0
- data/test/support/factories/structure_factory.rb +86 -0
- data/test/support/fixtures.rb +6 -0
- data/test/support/kissmetrics/core_api.rb +542 -0
- data/{spec/spec_helper.rb → test/test_helper.rb} +7 -1
- metadata +73 -25
- data/lib/skeleton/config.rb +0 -37
- data/lib/skeleton/documentation.rb +0 -17
- data/lib/skeleton/example.rb +0 -31
- data/lib/skeleton/headers.rb +0 -50
- data/lib/skeleton/helpers/controller_helpers.rb +0 -25
- data/lib/skeleton/info.rb +0 -40
- data/lib/skeleton/item.rb +0 -99
- data/lib/skeleton/responses.rb +0 -59
- data/lib/skeleton/scopes.rb +0 -24
- data/lib/skeleton/security_definitions.rb +0 -46
- data/lib/skeleton/security_requirement.rb +0 -29
- data/spec/integrations/use_case_spec.rb +0 -131
- data/spec/skeleton/operation_spec.rb +0 -113
- data/spec/skeleton/serializers/contact_spec.rb +0 -30
- data/spec/skeleton/serializers/documentation_spec.rb +0 -23
- data/spec/skeleton/serializers/header_spec.rb +0 -57
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'multi_json'
|
3
|
+
require 'json-schema'
|
4
|
+
|
5
|
+
require 'skeleton/serializers/swagger'
|
6
|
+
|
7
|
+
describe 'Validate complex schemas' do
|
8
|
+
context 'KISSmetrics Core API' do
|
9
|
+
it 'conforms to the Swagger v2.0 Schema' do
|
10
|
+
# JSON Validator will reach out and grab this draft. This is to avoid
|
11
|
+
# the intermittent errors that occur
|
12
|
+
stub_request(:get, "http://json-schema.org/draft-04/schema")
|
13
|
+
.to_return({
|
14
|
+
status: 200,
|
15
|
+
body: Fixtures.read('json-schema-draft-04.json')
|
16
|
+
})
|
17
|
+
|
18
|
+
structure = KISSmetrics::CoreAPI.structure
|
19
|
+
hash = Skeleton::Serializers::Swagger.new(structure).to_h
|
20
|
+
schema = MultiJson.load(Fixtures.read('schema.json'))
|
21
|
+
|
22
|
+
errors = JSON::Validator.fully_validate(schema, hash, :errors_as_objects => true)
|
23
|
+
|
24
|
+
unless errors.empty?
|
25
|
+
messages = [
|
26
|
+
"JSON Validation Failed",
|
27
|
+
"Errors: #{errors.length}"
|
28
|
+
]
|
29
|
+
|
30
|
+
errors.each do |e|
|
31
|
+
messages << ' '.concat(e[:message])
|
32
|
+
messages << ' => '.concat(e[:fragment])
|
33
|
+
messages << ' => '.concat(e[:failed_attribute])
|
34
|
+
messages << ' => '.concat(e[:schema])
|
35
|
+
messages << ''
|
36
|
+
end
|
37
|
+
|
38
|
+
fail(messages.join("\n"))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'skeleton/graph'
|
4
|
+
|
5
|
+
module Skeleton
|
6
|
+
class GraphTest < Minitest::Test
|
7
|
+
def test_integration
|
8
|
+
graph = Skeleton::Graph.new
|
9
|
+
graph.register('Accounts', ['Meta', 'AccountData', 'Link'])
|
10
|
+
graph.register('Meta', 'Error')
|
11
|
+
graph.register('Error', 'Error')
|
12
|
+
graph.register('Accounts', 'AccountData')
|
13
|
+
graph.register('AccountData', 'Contact')
|
14
|
+
graph.register('Accounts', 'Link')
|
15
|
+
|
16
|
+
expected = Set.new(%w(Accounts Meta AccountData Link Contact Error))
|
17
|
+
actual = Set.new
|
18
|
+
graph.each_dependent_for('Accounts') { |n| actual.add(n) }
|
19
|
+
assert_equal(expected, actual)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'skeleton'
|
4
|
+
|
5
|
+
module Skeleton
|
6
|
+
class MapperTest < Minitest::Test
|
7
|
+
|
8
|
+
def structure
|
9
|
+
@structure ||= Skeleton::Structure.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup
|
13
|
+
structure.configure do
|
14
|
+
define_model('Link') do
|
15
|
+
describe('The link object used for api discovery')
|
16
|
+
required(:href, type: 'string')
|
17
|
+
required(:rel, type: 'string')
|
18
|
+
optional(:templated, type: 'boolean')
|
19
|
+
optional(:name, type: 'string')
|
20
|
+
end
|
21
|
+
|
22
|
+
define_model('Error') do
|
23
|
+
describe('Represents an error')
|
24
|
+
required(:message, type: 'string')
|
25
|
+
optional(:field, type: 'string')
|
26
|
+
optional(:errors, type: 'array', items: { ref: 'Error' })
|
27
|
+
end
|
28
|
+
|
29
|
+
define_model('Meta') do
|
30
|
+
describe('The meta information regarding the request')
|
31
|
+
required(:status, type: 'integer')
|
32
|
+
optional(:message, type: 'string')
|
33
|
+
optional(:errors, type: 'array', items: { ref: 'Error' })
|
34
|
+
end
|
35
|
+
|
36
|
+
define_model('ErrorResponse') do
|
37
|
+
describe('The information when there is an issue with a request')
|
38
|
+
required(:meta, ref: 'Meta')
|
39
|
+
required(:links, type: 'array', items: { ref: 'Link' })
|
40
|
+
end
|
41
|
+
|
42
|
+
define_model('Contact') do
|
43
|
+
optional(:name, type: 'string')
|
44
|
+
optional(:country, type: 'string')
|
45
|
+
optional(:phone, type: 'string')
|
46
|
+
end
|
47
|
+
|
48
|
+
define_model('AccountData') do
|
49
|
+
required(:id, type: 'string', format: 'uuid')
|
50
|
+
required(:name, type: 'string')
|
51
|
+
required(:status, type: 'string', enum: %w(active canceled))
|
52
|
+
required(:created_at, type: 'string', format: 'date-time')
|
53
|
+
required(:updated_at, type: 'string', format: 'date-time')
|
54
|
+
required(:contact, ref: 'Contact')
|
55
|
+
optional(:links, type: 'array', items: { ref: 'Link' })
|
56
|
+
end
|
57
|
+
|
58
|
+
define_model('Account') do
|
59
|
+
required(:meta, ref: 'Meta')
|
60
|
+
required(:data, ref: 'AccountData')
|
61
|
+
required(:links, type: 'array', items: { ref: 'Link' })
|
62
|
+
end
|
63
|
+
|
64
|
+
define_model('Accounts') do
|
65
|
+
required(:meta, ref: 'Meta')
|
66
|
+
required(:data, type: 'array', items: { ref: 'AccountData' })
|
67
|
+
required(:links, type: 'array', items: { ref: 'Link' })
|
68
|
+
end
|
69
|
+
|
70
|
+
define_path('/accounts') do
|
71
|
+
get do
|
72
|
+
response(200) do
|
73
|
+
describe 'get a list of accounts'
|
74
|
+
schema(ref: 'Accounts')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end # end setup
|
80
|
+
|
81
|
+
def test_the_mapping
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'skeleton/parameter'
|
4
|
+
|
5
|
+
module Skeleton
|
6
|
+
class ParameterTests < Minitest::Test
|
7
|
+
def parameter
|
8
|
+
@parameter ||= Skeleton::Parameter.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_body?
|
12
|
+
parameter.location = 'body'
|
13
|
+
assert(parameter.body?)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_query?
|
17
|
+
parameter.location = 'query'
|
18
|
+
refute(parameter.body?)
|
19
|
+
assert(parameter.query?)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_path?
|
23
|
+
parameter.location = 'path'
|
24
|
+
refute(parameter.body?)
|
25
|
+
assert(parameter.path?)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_header?
|
29
|
+
parameter.location = 'header'
|
30
|
+
refute(parameter.body?)
|
31
|
+
assert(parameter.header?)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'skeleton/path'
|
4
|
+
|
5
|
+
module Skeleton
|
6
|
+
class PathTest < Minitest::Test
|
7
|
+
def setup
|
8
|
+
@path = Skeleton::Path.new
|
9
|
+
end
|
10
|
+
def test_get
|
11
|
+
@path.get do
|
12
|
+
end
|
13
|
+
assert(@path.operations.key?(:get), 'expected the get operation to be present')
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_put
|
17
|
+
@path.put do
|
18
|
+
end
|
19
|
+
assert(@path.operations.key?(:put), 'expected the put operation to be present')
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_post
|
23
|
+
@path.post do
|
24
|
+
end
|
25
|
+
assert(@path.operations.key?(:post), 'expected the post operation to be present')
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_patch
|
29
|
+
@path.patch do
|
30
|
+
end
|
31
|
+
assert(@path.operations.key?(:patch), 'expected the patch operation to be present')
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_delete
|
35
|
+
@path.delete do
|
36
|
+
end
|
37
|
+
assert(@path.operations.key?(:delete), 'expected the delete operation to be present')
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_options
|
41
|
+
@path.options do
|
42
|
+
end
|
43
|
+
assert(@path.operations.key?(:options), 'expected the options operation to be present')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Skeleton
|
4
|
+
module Serializers
|
5
|
+
class OptionsTest < Minitest::Test
|
6
|
+
def structure
|
7
|
+
@structure ||= Skeleton::Structure.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def serializer
|
11
|
+
@serializer ||= Skeleton::Serializers::Options.new(structure, path: '/accounts')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_deeply_nested_dependencies
|
15
|
+
Factories::StructureFactory.configure_basic_structure(structure)
|
16
|
+
hash = serializer.to_h
|
17
|
+
|
18
|
+
refute_nil(hash[:definitions], 'Expected definitions to be present')
|
19
|
+
refute_nil(hash[:definitions]['Accounts'])
|
20
|
+
refute_nil(hash[:definitions]['AccountData'])
|
21
|
+
refute_nil(hash[:definitions]['Meta'])
|
22
|
+
refute_nil(hash[:definitions]['Error'])
|
23
|
+
refute_nil(hash[:definitions]['Link'])
|
24
|
+
refute_nil(hash[:definitions]['Contact'])
|
25
|
+
refute_nil(hash[:definitions]['ErrorResponse'])
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_empty_structure
|
29
|
+
assert_raises(Skeleton::Error) { serializer.to_h }
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_reference_non_existant_model
|
33
|
+
structure.define_path('/accounts') do
|
34
|
+
get do
|
35
|
+
response(200) do
|
36
|
+
schema(ref: 'Foo')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
structure.define_model('Foo') do
|
41
|
+
property(:bar, type: 'array', items: { ref: 'Bar' })
|
42
|
+
end
|
43
|
+
|
44
|
+
hash = serializer.to_h
|
45
|
+
|
46
|
+
refute_nil(hash[:definitions], 'Expected definitions to be present')
|
47
|
+
refute_nil(hash[:definitions]['Foo'], 'Expected Foo to be present')
|
48
|
+
assert_empty(hash[:definitions]['Bar'], 'Expected Bar to be empty')
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_path_that_does_not_exist
|
52
|
+
structure.define_model('Foo') do
|
53
|
+
property(:bar, type: 'array', items: { ref: 'Bar' })
|
54
|
+
end
|
55
|
+
|
56
|
+
assert_raises(Skeleton::Error) do
|
57
|
+
serializer.to_h
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_path_not_specified
|
62
|
+
assert_raises(Skeleton::Error) do
|
63
|
+
Skeleton::Serializers::Options.new(structure)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Skeleton
|
4
|
+
module Serializers
|
5
|
+
class SwaggerTest < Minitest::Test
|
6
|
+
def structure
|
7
|
+
@structure ||= Skeleton::Structure.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def serializer
|
11
|
+
@serializer ||= Skeleton::Serializers::Swagger.new(structure)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_empty_structure
|
15
|
+
result = serializer.to_h
|
16
|
+
assert_equal('2.0', result[:swagger])
|
17
|
+
refute_nil(result[:info], 'expected the info hash to be present')
|
18
|
+
|
19
|
+
assert(result.key?(:basePath))
|
20
|
+
assert(result.key?(:host))
|
21
|
+
assert_empty(result[:schemes])
|
22
|
+
assert_empty(result[:consumes])
|
23
|
+
assert_empty(result[:produces])
|
24
|
+
assert_empty(result[:tags])
|
25
|
+
assert_empty(result[:paths])
|
26
|
+
assert_empty(result[:definitions])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'skeleton'
|
2
|
+
|
3
|
+
module Factories
|
4
|
+
class StructureFactory
|
5
|
+
def self.build_basic_structure
|
6
|
+
structure = Skeleton::Structure.new
|
7
|
+
configure_basic_structure(structure)
|
8
|
+
structure
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.configure_basic_structure(structure)
|
12
|
+
structure.configure do
|
13
|
+
define_model('Link') do
|
14
|
+
describe('The link object used for api discovery')
|
15
|
+
required(:href, type: 'string')
|
16
|
+
required(:rel, type: 'string')
|
17
|
+
optional(:templated, type: 'boolean')
|
18
|
+
optional(:name, type: 'string')
|
19
|
+
end
|
20
|
+
|
21
|
+
define_model('Error') do
|
22
|
+
describe('Represents an error')
|
23
|
+
required(:message, type: 'string')
|
24
|
+
optional(:field, type: 'string')
|
25
|
+
optional(:errors, type: 'array', items: { ref: 'Error' })
|
26
|
+
end
|
27
|
+
|
28
|
+
define_model('Meta') do
|
29
|
+
describe('The meta information regarding the request')
|
30
|
+
required(:status, type: 'integer')
|
31
|
+
optional(:message, type: 'string')
|
32
|
+
optional(:errors, type: 'array', items: { ref: 'Error' })
|
33
|
+
end
|
34
|
+
|
35
|
+
define_model('ErrorResponse') do
|
36
|
+
describe('The information when there is an issue with a request')
|
37
|
+
required(:meta, ref: 'Meta')
|
38
|
+
required(:links, type: 'array', items: { ref: 'Link' })
|
39
|
+
end
|
40
|
+
|
41
|
+
define_model('Contact') do
|
42
|
+
optional(:name, type: 'string')
|
43
|
+
optional(:country, type: 'string')
|
44
|
+
optional(:phone, type: 'string')
|
45
|
+
end
|
46
|
+
|
47
|
+
define_model('AccountData') do
|
48
|
+
required(:id, type: 'string', format: 'uuid')
|
49
|
+
required(:name, type: 'string')
|
50
|
+
required(:status, type: 'string', enum: %w(active canceled))
|
51
|
+
required(:created_at, type: 'string', format: 'date-time')
|
52
|
+
required(:updated_at, type: 'string', format: 'date-time')
|
53
|
+
required(:contact, ref: 'Contact')
|
54
|
+
optional(:links, type: 'array', items: { ref: 'Link' })
|
55
|
+
end
|
56
|
+
|
57
|
+
define_model('Account') do
|
58
|
+
required(:meta, ref: 'Meta')
|
59
|
+
required(:data, ref: 'AccountData')
|
60
|
+
required(:links, type: 'array', items: { ref: 'Link' })
|
61
|
+
end
|
62
|
+
|
63
|
+
define_model('Accounts') do
|
64
|
+
required(:meta, ref: 'Meta')
|
65
|
+
required(:data, type: 'array', items: { ref: 'AccountData' })
|
66
|
+
required(:links, type: 'array', items: { ref: 'Link' })
|
67
|
+
end
|
68
|
+
|
69
|
+
define_path('/accounts') do
|
70
|
+
get do
|
71
|
+
response(200) do
|
72
|
+
describe 'get a list of accounts'
|
73
|
+
schema(ref: 'Accounts')
|
74
|
+
end
|
75
|
+
response(403) do
|
76
|
+
describe 'access denied'
|
77
|
+
schema(ref: 'ErrorResponse')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
structure
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|