openapi_rest 0.0.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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +141 -0
  4. data/Rakefile +11 -0
  5. data/bin/console +14 -0
  6. data/bin/setup +8 -0
  7. data/lib/generators/openapi_rest/install_generator.rb +11 -0
  8. data/lib/generators/openapi_rest/openapi_doc.rb +3 -0
  9. data/lib/generators/templates/api_docs.yml +162 -0
  10. data/lib/openapi_rest.rb +22 -0
  11. data/lib/openapi_rest/api_config.rb +12 -0
  12. data/lib/openapi_rest/api_doc.rb +19 -0
  13. data/lib/openapi_rest/api_doc_parser.rb +110 -0
  14. data/lib/openapi_rest/api_model.rb +36 -0
  15. data/lib/openapi_rest/api_parameters.rb +76 -0
  16. data/lib/openapi_rest/api_validator.rb +20 -0
  17. data/lib/openapi_rest/extension.rb +35 -0
  18. data/lib/openapi_rest/operations/filter.rb +24 -0
  19. data/lib/openapi_rest/operations/paginate.rb +19 -0
  20. data/lib/openapi_rest/operations/sort.rb +27 -0
  21. data/lib/openapi_rest/query_builder.rb +70 -0
  22. data/lib/openapi_rest/query_response.rb +89 -0
  23. data/lib/openapi_rest/railtie.rb +9 -0
  24. data/lib/openapi_rest/rest_renderer.rb +75 -0
  25. data/lib/openapi_rest/validators/format.rb +24 -0
  26. data/lib/openapi_rest/validators/pattern.rb +21 -0
  27. data/lib/openapi_rest/version.rb +3 -0
  28. data/test/openapi_rest/api_config_test.rb +9 -0
  29. data/test/openapi_rest/api_doc_parser_test.rb +71 -0
  30. data/test/openapi_rest/api_doc_test.rb +15 -0
  31. data/test/openapi_rest/api_model_test.rb +49 -0
  32. data/test/openapi_rest/api_parameters_test.rb +57 -0
  33. data/test/openapi_rest/api_validator_test.rb +23 -0
  34. data/test/openapi_rest/query_builder_test.rb +32 -0
  35. data/test/openapi_rest/query_response_test.rb +129 -0
  36. data/test/spec_helper.rb +8 -0
  37. data/test/support/data.rb +3 -0
  38. data/test/support/models.rb +3 -0
  39. data/test/support/schema.rb +13 -0
  40. metadata +139 -0
@@ -0,0 +1,9 @@
1
+ module OpenAPIRest
2
+ class Railtie < Rails::Railtie
3
+ initializer "openapi_rest.action_controller" do
4
+ ActiveSupport.on_load :action_controller do
5
+ include OpenAPIRest::Extension::ClassMethods
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,75 @@
1
+ module OpenAPIRest
2
+ ###
3
+ # Rest Response Renderer
4
+ #
5
+ class RestRenderer
6
+ attr_reader :controller
7
+ attr_reader :response
8
+
9
+ def initialize(args)
10
+ @controller = args[:controller]
11
+ @response = args[:response]
12
+ end
13
+
14
+ def render
15
+ unless response.is_a?(OpenAPIRest::QueryResponse)
16
+ controller.render(response)
17
+ return
18
+ end
19
+
20
+ return controller.render(error_response) if response.errors?
21
+
22
+ method = controller.request.request_method_symbol
23
+ return controller.render(nothing: true, status: 204) if [:delete, :patch, :put].include?(method)
24
+
25
+ if method == :post
26
+ path = "#{controller.openapi_path[:namespace]}#{response.resource}_path"
27
+ controller.render(json: to_json_response, status: 201, location: controller.send(path, response.results))
28
+ return
29
+ end
30
+
31
+ controller.render(json: to_json_response)
32
+ end
33
+
34
+ private
35
+
36
+ def to_json_response
37
+ if response.single?
38
+ single_response
39
+ else
40
+ collection_response
41
+ end
42
+ end
43
+
44
+ def fetch(opts)
45
+ response.results.as_json(opts.merge(only: [],
46
+ methods: response.fields))
47
+ end
48
+
49
+ def collection_response(opts = {})
50
+ resp = {}
51
+ resp[response.entity] = fetch(opts)
52
+ success_response(resp)
53
+ end
54
+
55
+ def single_response(opts = {})
56
+ success_response(fetch(opts))
57
+ end
58
+
59
+ def success_response(obj)
60
+ obj.to_json
61
+ end
62
+
63
+ def error_response
64
+ error_code = 400
65
+ {
66
+ status: error_code,
67
+ json: {
68
+ status: error_code,
69
+ message: Rack::Utils::HTTP_STATUS_CODES[error_code],
70
+ errors: response.errors
71
+ }
72
+ }
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,24 @@
1
+ module OpenAPIRest
2
+ module Validators
3
+ ###
4
+ # Rest format validator
5
+ #
6
+ class Format
7
+ def initialize(format, value)
8
+ @format = format
9
+ @value = value
10
+ end
11
+
12
+ def valid?
13
+ return @value.is_a?(Numeric) if @format == 'int64' || @format == 'int32'
14
+ return !DateTimeHelper.in_utc(@value).nil? if @format == 'date-time'
15
+
16
+ true
17
+ end
18
+
19
+ def error(key)
20
+ { key => "not a #{@format}" }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ module OpenAPIRest
2
+ module Validators
3
+ ###
4
+ # Rest pattern validator
5
+ #
6
+ class Pattern
7
+ def initialize(format, value)
8
+ @format = format
9
+ @value = value
10
+ end
11
+
12
+ def valid?
13
+ Regexp.new(@format).match(@value)
14
+ end
15
+
16
+ def error(key)
17
+ { key => "invalid format #{@format}" }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module OpenAPIRest
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,9 @@
1
+ require 'minitest/autorun'
2
+ require 'openapi_rest/api_config'
3
+
4
+ describe OpenAPIRest::ApiConfig do
5
+ it 'initialize document correctly' do
6
+ api_config = OpenAPIRest::ApiConfig.new(document: 'mylocaldoc')
7
+ assert_equal(api_config.document, 'mylocaldoc')
8
+ end
9
+ end
@@ -0,0 +1,71 @@
1
+ require 'minitest/autorun'
2
+ require 'openapi_rest/api_doc_parser'
3
+
4
+ describe OpenAPIRest::ApiDocParser do
5
+ before do
6
+ OpenAPIRest::ApiDoc.configure do |c|
7
+ c.document = ::YAML::load_file('lib/generators/templates/api_docs.yml')
8
+ end
9
+
10
+ @api_doc_parser = OpenAPIRest::ApiDocParser.new(path: '/products',
11
+ method: 'get')
12
+ end
13
+
14
+ ['definitions', 'parameters', 'paths'].each do |method_name|
15
+ it "##{method_name}" do
16
+ name = OpenAPIRest::ApiDoc.document.fetch(method_name, {})
17
+ refute_nil(@api_doc_parser.send(method_name))
18
+ assert_equal(@api_doc_parser.send(method_name).to_s, name)
19
+ end
20
+ end
21
+
22
+ it '#find(key)' do
23
+ definitions = OpenAPIRest::ApiDoc.document.fetch('definitions', {})
24
+ assert_equal(@api_doc_parser.definitions.find('Product').to_s, definitions.fetch('Product'))
25
+ end
26
+
27
+ it '#base_path' do
28
+ assert_equal(@api_doc_parser.base_path, '/v1')
29
+ end
30
+
31
+ it '#find_path' do
32
+ paths = OpenAPIRest::ApiDoc.document.fetch('paths', {}).fetch('/products').fetch('get')
33
+ assert_equal(@api_doc_parser.find_path.to_s, paths)
34
+ end
35
+
36
+ it '#properties' do
37
+ properties = OpenAPIRest::ApiDoc.document.fetch('definitions', {}).fetch('Product').fetch('properties')
38
+ assert_equal(@api_doc_parser.definitions.find('Product').properties.to_s, properties)
39
+ end
40
+
41
+ describe '#schema' do
42
+ it 'with items' do
43
+ product = OpenAPIRest::ApiDoc.document.fetch('definitions', {}).fetch('Product')
44
+ assert_equal(@api_doc_parser.find_path.responses.find(200).schema.to_s, product)
45
+ end
46
+
47
+ it 'with ref' do
48
+ error = OpenAPIRest::ApiDoc.document.fetch('definitions', {}).fetch('Error')
49
+ assert_equal(@api_doc_parser.find_path.responses.find('default').schema.to_s, error)
50
+ end
51
+ end
52
+
53
+ it '#find_parameters' do
54
+ assert_equal(@api_doc_parser.find_path.find_parameters, { 'latitude' => 'latitude', 'longitude' => 'longitude' })
55
+ end
56
+
57
+ it '#responses' do
58
+ responses = OpenAPIRest::ApiDoc.document.fetch('paths', {}).fetch('/products').fetch('get').fetch('responses')
59
+ assert_equal(@api_doc_parser.find_path.responses.to_s, responses)
60
+ end
61
+
62
+ it '#responses' do
63
+ keys = OpenAPIRest::ApiDoc.document.fetch('paths', {}).fetch('/products').fetch('get').fetch('responses').keys
64
+ assert_equal(@api_doc_parser.find_path.responses.keys, keys)
65
+ end
66
+
67
+ it '#[](key)' do
68
+ products = OpenAPIRest::ApiDoc.document.fetch('paths', {}).fetch('/products')
69
+ assert_equal(@api_doc_parser.paths['/products'].to_s, products)
70
+ end
71
+ end
@@ -0,0 +1,15 @@
1
+ require 'minitest/autorun'
2
+ require 'openapi_rest/api_doc'
3
+ require 'yaml'
4
+
5
+ describe OpenAPIRest::ApiDoc do
6
+ before do
7
+ OpenAPIRest::ApiDoc.configure do |c|
8
+ c.document = ::YAML::load_file('lib/generators/templates/api_docs.yml')
9
+ end
10
+ end
11
+
12
+ it '#document' do
13
+ refute_nil(OpenAPIRest::ApiDoc.document)
14
+ end
15
+ end
@@ -0,0 +1,49 @@
1
+ require 'minitest/autorun'
2
+ require 'spec_helper'
3
+ require 'action_controller'
4
+ require 'openapi_rest/api_model'
5
+ require 'openapi_rest/api_parameters'
6
+ require 'openapi_rest/api_validator'
7
+ require 'openapi_rest/query_builder'
8
+ require 'openapi_rest/query_response'
9
+ require 'openapi_rest/operations/filter'
10
+ require 'openapi_rest/operations/paginate'
11
+ require 'openapi_rest/operations/sort'
12
+
13
+ describe OpenAPIRest::ApiModel do
14
+ before do
15
+ OpenAPIRest::ApiDoc.configure do |c|
16
+ c.document = ::YAML::load_file('lib/generators/templates/api_docs.yml')
17
+ end
18
+
19
+ @api_model = OpenAPIRest::ApiModel.new(:product)
20
+ end
21
+
22
+ it '#model' do
23
+ assert_equal(@api_model.model, Product)
24
+ end
25
+
26
+ it '#build' do
27
+ params = ActionController::Parameters.new(openapi_path: { path: '/products', method: 'post' },
28
+ product: { product_id: '1234' })
29
+ api_product = @api_model.build(params)
30
+
31
+ refute_nil(api_product)
32
+ assert_kind_of(OpenAPIRest::QueryResponse, api_product)
33
+ end
34
+
35
+ it '#find' do
36
+ params = ActionController::Parameters.new(openapi_path: { path: '/products/0000', method: 'get' },
37
+ product: { product_id: '0000' })
38
+ response = @api_model.find(params, product_id: '0000')
39
+
40
+ assert_equal(response.results, Product.find_by(product_id: '0000'))
41
+ end
42
+
43
+ it '#where' do
44
+ params = ActionController::Parameters.new(openapi_path: { path: '/products', method: 'get' })
45
+ response = @api_model.where(params)
46
+
47
+ assert_equal(response.results, Product.all.to_a)
48
+ end
49
+ end
@@ -0,0 +1,57 @@
1
+ require 'minitest/autorun'
2
+ require 'spec_helper'
3
+ require 'action_controller'
4
+ require 'openapi_rest/api_parameters'
5
+
6
+ describe OpenAPIRest::ApiParameters do
7
+ before do
8
+ OpenAPIRest::ApiDoc.configure do |c|
9
+ c.document = ::YAML::load_file('lib/generators/templates/api_docs.yml')
10
+ end
11
+
12
+ params = ActionController::Parameters.new(openapi_path: { path: '/products', method: 'post' },
13
+ product: { product_id: '0000' })
14
+
15
+ model = OpenAPIRest::ApiModel.new(:product)
16
+
17
+ @api_parameters = OpenAPIRest::ApiParameters.new(api_model: model,
18
+ params: params,
19
+ openapi_path: params[:openapi_path])
20
+ end
21
+
22
+ it '#initialize' do
23
+ refute_nil(@api_parameters)
24
+ end
25
+
26
+ describe '#valid?' do
27
+ it 'with errors' do
28
+ model = OpenAPIRest::ApiModel.new(:product)
29
+ params = ActionController::Parameters.new(product_id: '0000')
30
+
31
+ api_parameters_with_error = OpenAPIRest::ApiParameters.new(api_model: model,
32
+ params: params,
33
+ openapi_path: { path: '/products', method: 'post' })
34
+
35
+ assert_equal(api_parameters_with_error.valid?, false)
36
+ refute_empty(api_parameters_with_error.validation_errors)
37
+ end
38
+
39
+ it 'without errors' do
40
+ assert_equal(@api_parameters.valid?, true)
41
+ assert_empty(@api_parameters.validation_errors)
42
+ end
43
+ end
44
+
45
+ it '#response_permitted_params' do
46
+ params = ActionController::Parameters.new(openapi_path: { path: '/products', method: 'get' })
47
+
48
+ model = OpenAPIRest::ApiModel.new(:product)
49
+
50
+ api_parameters = OpenAPIRest::ApiParameters.new(api_model: model,
51
+ params: params,
52
+ openapi_path: params[:openapi_path])
53
+
54
+ assert_equal(api_parameters.response_permitted_params, [:product_id, :description, :name, :capacity,
55
+ :image])
56
+ end
57
+ end
@@ -0,0 +1,23 @@
1
+ require 'minitest/autorun'
2
+ require 'openapi_rest/api_validator'
3
+ require 'openapi_rest/validators/format'
4
+ require 'openapi_rest/validators/pattern'
5
+
6
+ describe OpenAPIRest::ApiValidator do
7
+ describe '#evaluate' do
8
+ describe 'with integers' do
9
+ before do
10
+ @params = {}
11
+ @params['format'] = 'int64'
12
+ end
13
+
14
+ it 'be valid' do
15
+ OpenAPIRest::ApiValidator.new(@params).evaluate([:id], { id: 123 })
16
+ end
17
+
18
+ it 'not be valid' do
19
+ OpenAPIRest::ApiValidator.new(@params).evaluate([:id], { id: 'test' })
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ require 'minitest/autorun'
2
+
3
+ describe OpenAPIRest::QueryBuilder do
4
+ before do
5
+ OpenAPIRest::ApiDoc.configure do |c|
6
+ c.document = ::YAML::load_file('lib/generators/templates/api_docs.yml')
7
+ end
8
+
9
+ @api_model = OpenAPIRest::ApiModel.new(:product)
10
+ end
11
+
12
+ describe '' do
13
+ before do
14
+ params = ActionController::Parameters.new(openapi_path: { path: '/products', method: 'post' },
15
+ product: { product_id: '2222' })
16
+ @query_builder = OpenAPIRest::QueryBuilder.new(@api_model, params.merge!(operation: :create))
17
+ end
18
+
19
+ it 'check default params' do
20
+ assert_empty(@query_builder.query)
21
+ assert_nil(@query_builder.sort)
22
+ assert_equal(@query_builder.limit, 10)
23
+ assert_equal(@query_builder.offset, 0)
24
+ assert_empty(@query_builder.fields)
25
+ assert_equal(@query_builder.single_result?, true)
26
+ assert_equal(@query_builder.single?, true)
27
+ assert_equal(@query_builder.resource, 'product')
28
+ assert_equal(@query_builder.entity, 'products')
29
+ refute_nil(@query_builder.response)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,129 @@
1
+ require 'minitest/autorun'
2
+
3
+ describe OpenAPIRest::QueryResponse do
4
+ before do
5
+ OpenAPIRest::ApiDoc.configure do |c|
6
+ c.document = ::YAML::load_file('lib/generators/templates/api_docs.yml')
7
+ end
8
+
9
+ @api_model = OpenAPIRest::ApiModel.new(:product)
10
+ end
11
+
12
+ describe '#create_resource' do
13
+ describe 'without errors' do
14
+ before do
15
+ params = ActionController::Parameters.new(openapi_path: { path: '/products', method: 'post' },
16
+ product: { product_id: '2222' })
17
+ query_builder = OpenAPIRest::QueryBuilder.new(@api_model, params.merge!(operation: :create))
18
+ @response = query_builder.response
19
+ @response.create_resource
20
+ end
21
+
22
+ it 'check default params' do
23
+ product_created = Product.find_by(product_id: '2222')
24
+
25
+ assert_empty(@response.errors)
26
+ assert_equal(@response.errors?, false)
27
+ refute_nil(@response)
28
+ assert_equal(@response.results, product_created)
29
+
30
+ refute_nil(product_created)
31
+ end
32
+ end
33
+
34
+ describe 'with errors' do
35
+ before do
36
+ params = ActionController::Parameters.new(openapi_path: { path: '/products', method: 'post' }, product: {})
37
+ query_builder = OpenAPIRest::QueryBuilder.new(@api_model, params.merge!(operation: :create))
38
+ @response = query_builder.response
39
+ @response.create_resource
40
+ end
41
+
42
+ it 'check default params' do
43
+ refute_nil(@response)
44
+ refute_empty(@response.errors)
45
+ assert_equal(@response.errors?, true)
46
+ end
47
+ end
48
+ end
49
+
50
+ describe '#update_resource' do
51
+ describe 'without errors' do
52
+ before do
53
+ params = ActionController::Parameters.new(openapi_path: { path: '/products/{id}', method: 'patch' },
54
+ product: { name: 'test product' })
55
+ query_builder = OpenAPIRest::QueryBuilder.new(@api_model, params.merge!(operation: :squery,
56
+ query: { product_id: '2222' }))
57
+ @response = query_builder.response
58
+ @response.update_resource
59
+ end
60
+
61
+ it 'check default params' do
62
+ product_updated = Product.find_by(product_id: '2222')
63
+
64
+ assert_empty(@response.errors)
65
+ assert_equal(@response.errors?, false)
66
+ refute_nil(@response)
67
+ assert_equal(@response.results, product_updated)
68
+
69
+ refute_nil(product_updated)
70
+ assert_equal(product_updated.name, 'test product')
71
+ end
72
+ end
73
+
74
+ describe 'with wrong params' do
75
+ before do
76
+ params = ActionController::Parameters.new(openapi_path: { path: '/products/{id}', method: 'patch' },
77
+ product: { capacity: 'test' })
78
+ query_builder = OpenAPIRest::QueryBuilder.new(@api_model, params.merge!(operation: :squery,
79
+ query: { product_id: '2222' }))
80
+ @response = query_builder.response
81
+ @response.update_resource
82
+ end
83
+
84
+ it 'check default params' do
85
+ product_updated = Product.find_by(product_id: '2222')
86
+
87
+ refute_nil(@response)
88
+ assert_equal(@response.results, product_updated)
89
+
90
+ assert_nil(product_updated.capacity)
91
+ end
92
+ end
93
+ end
94
+
95
+ describe '#delete_resource' do
96
+ describe 'without errors' do
97
+ before do
98
+ @product_deleted = Product.find_by(product_id: '5555')
99
+
100
+ params = ActionController::Parameters.new(openapi_path: { path: '/products/{id}', method: 'delete' })
101
+ query_builder = OpenAPIRest::QueryBuilder.new(@api_model, params.merge!(operation: :squery,
102
+ query: { product_id: '5555' }))
103
+ @response = query_builder.response
104
+ @response.delete_resource
105
+ end
106
+
107
+ it 'check default params' do
108
+ assert_empty(@response.errors)
109
+ assert_equal(@response.errors?, false)
110
+ assert_equal(@response.results?, true)
111
+ assert_equal(@response.results, @product_deleted)
112
+ end
113
+ end
114
+
115
+ describe 'non existing' do
116
+ before do
117
+ params = ActionController::Parameters.new(openapi_path: { path: '/products/{id}', method: 'delete' })
118
+ query_builder = OpenAPIRest::QueryBuilder.new(@api_model, params.merge!(operation: :squery,
119
+ query: { product_id: '4444' }))
120
+ @response = query_builder.response
121
+ @response.delete_resource
122
+ end
123
+
124
+ it 'check default params' do
125
+ assert_equal(@response.results?, false)
126
+ end
127
+ end
128
+ end
129
+ end