openapi_rest 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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