swalidate 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bfe97d384e09f73d2de99aa29853d792656a67e1
4
- data.tar.gz: 450d059e60539ad1930f3065522cce1443605e12
3
+ metadata.gz: c3459b3c0c2f919ba4c550703f8398277a7b3869
4
+ data.tar.gz: 1d4bc1e86843aaf3f69874f97df329c4519b0785
5
5
  SHA512:
6
- metadata.gz: d124d24c33f76db15a62c2ee6cc9104d8bfeedfea39cd4fead045caab74fbe567abe14bc53b69750dee62b0749e6c6147990fba00d4f394dc5f802ff42da2224
7
- data.tar.gz: 19aaacc3e0fe2a4ce13f286f7ab1b838a996b8ab69b66a224b5de4e0b40eac6f360092245706de7aa8da6a7f1a1af541ef498ad328de563a755040d34bca832d
6
+ metadata.gz: cd7b44bf8a7ad42527403122cb12cbe38c9340a433e5ba92efbad604b606e38d458b89e11f5fa243e014c83a04a43fa18c3b221f8c663800e294df7777333134
7
+ data.tar.gz: aa91c4ad4bf33c4c220c000202f774c23fe6c46a3919954e6fd0cdc6d933551a34b2002a13d0e2f5d594378f502ff4060beeef06347c366165c2e2d9d0e84bc1
data/.rubocop.yml ADDED
@@ -0,0 +1,7 @@
1
+ # require: rubocop-rspec
2
+
3
+ Metrics/LineLength:
4
+ Max: 100
5
+
6
+ Style/Documentation:
7
+ Enabled: false
data/.travis.yml CHANGED
@@ -3,3 +3,5 @@ language: ruby
3
3
  rvm:
4
4
  - 2.2.1
5
5
  before_install: gem install bundler -v 1.14.3
6
+ script:
7
+ rake spec rubocop
data/README.md CHANGED
@@ -22,7 +22,14 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- TODO: Write usage instructions here
25
+ ```ruby
26
+ swalidate_config = {
27
+ file_path: 'path.yaml', # swagger config file. example of app root
28
+ subdomain: 'api', # validation applies only to this subdomain
29
+ path_prefix: '/v1' # validation applies only to the paths starting with path_prefix
30
+ }
31
+ config.middleware.insert_after ActionDispatch::ParamsParser, Swalidate::Middleware, swalidate_config
32
+ ```
26
33
 
27
34
  ## Development
28
35
 
data/Rakefile CHANGED
@@ -1,6 +1,9 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ require 'rubocop/rake_task'
7
+ RuboCop::RakeTask.new
8
+
9
+ task default: :spec
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "swalidate"
3
+ require 'bundler/setup'
4
+ require 'swalidate'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +10,5 @@ require "swalidate"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
13
+ require 'irb'
14
14
  IRB.start(__FILE__)
@@ -0,0 +1,13 @@
1
+ module Swalidate
2
+ class Endpoint
3
+ attr_reader :parameters
4
+
5
+ def initialize(detail)
6
+ @parameters = Array(detail && detail['parameters'])
7
+ end
8
+
9
+ def should_validate?
10
+ @parameters.any?
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,51 @@
1
+ module Swalidate
2
+ class Middleware
3
+ def initialize(app, options = {})
4
+ @app = app
5
+ @schema = Swalidate::Schema.new(options[:file_path])
6
+ # TODO: puts a log message when not found and dont try to validate
7
+
8
+ @subdomain = options[:subdomain]
9
+ @path_prefix = options[:path_prefix]
10
+ end
11
+
12
+ def call(env)
13
+ @request = ActionDispatch::Request.new(env)
14
+ @endpoint = @schema.endpoint(@request.method, @request.path.gsub(@path_prefix.to_s, '').sub(/\.[^.]+\z/, ''))
15
+
16
+ if should_validate?
17
+ validator = Swalidate::Validator::Main.new(@endpoint, @request.params)
18
+ validator.call
19
+ return error_response(validator.errors) unless validator.valid?
20
+ end
21
+
22
+ @app.call(env)
23
+ end
24
+
25
+ private
26
+
27
+ def error_response(errors)
28
+ [
29
+ 400,
30
+ { 'Content-Type' => 'application/vnd.api+json' },
31
+ [{ errors: errors }.to_json]
32
+ ]
33
+ end
34
+
35
+ def should_validate?
36
+ valid_subdomain? && valid_path_prefix? && valid_path?
37
+ end
38
+
39
+ def valid_subdomain?
40
+ @subdomain.to_s == @request.subdomain.to_s
41
+ end
42
+
43
+ def valid_path_prefix?
44
+ @request.path =~ Regexp.new(@path_prefix.to_s)
45
+ end
46
+
47
+ def valid_path?
48
+ @endpoint.should_validate?
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,17 @@
1
+ module Swalidate
2
+ class Schema
3
+ attr_reader :paths, :definitions
4
+
5
+ def initialize(file_path)
6
+ swagger = Swagger.load(file_path)
7
+ # TODO: error handling for files
8
+
9
+ @paths = swagger.paths
10
+ @definitions = swagger.definitions
11
+ end
12
+
13
+ def endpoint(method, path)
14
+ Swalidate::Endpoint.new(paths[path] && paths[path][method.downcase])
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,94 @@
1
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types
2
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields-8
3
+
4
+ require 'date'
5
+
6
+ module Swalidate
7
+ module Types
8
+ class Main
9
+ attr_reader :param, :casted_value, :errors
10
+
11
+ def initialize(param, value)
12
+ @param = param
13
+ @errors = []
14
+ @casted_value = cast_value(value)
15
+ end
16
+
17
+ def valid?
18
+ return true if casted_value == 'NilObject.new'
19
+
20
+ # TODO:
21
+ # errors << {
22
+ # parameter: param['name'],
23
+ # message: "'#{param['name']}' can be minimum #{param['minimum']}"
24
+ # }
25
+
26
+ case casted_value
27
+ when Numeric
28
+ if param['minimum'] && casted_value < param['minimum']
29
+ @errors << {
30
+ 'message' => "'#{param['name']}' can be minimum #{param['minimum']}"
31
+ }
32
+ end
33
+ if param['maximum'] && casted_value > param['maximum']
34
+ @errors << {
35
+ 'message' => "'#{param['name']}' can be maximum #{param['maximum']}"
36
+ }
37
+ end
38
+ when String
39
+ if param['minLength'] && casted_value.length < param['minLength']
40
+ @errors << {
41
+ 'message' => "Length of '#{param['name']}' can be minimum #{param['minLength']}"
42
+ }
43
+ end
44
+ if param['maxLength'] && casted_value.length > param['maxLength']
45
+ @errors << {
46
+ 'message' => "Length of '#{param['name']}' can be maximum #{param['maxLength']}"
47
+ }
48
+ end
49
+ if param['pattern'] && !(casted_value =~ Regexp.new(param['pattern']))
50
+ @errors << {
51
+ 'message' => "'#{param['name']}' is not fit to pattern #{param['pattern']}"
52
+ }
53
+ end
54
+ end
55
+
56
+ errors.empty?
57
+ end
58
+
59
+ private
60
+
61
+ def cast_value(value)
62
+ return 'NilObject.new' unless value # TODO: create a NilObject class
63
+
64
+ begin
65
+ case param['type']
66
+ when 'integer' then Integer(value)
67
+ when 'number' then Float(value)
68
+ when 'string'
69
+ case param['format']
70
+ # TODO: date parsing: https://xml2rfc.tools.ietf.org/public/rfc/html/rfc3339.html#anchor14
71
+ # 2015-02-01T00:00:00+00:00
72
+ # Date.rfc3339(value)
73
+ # DateTime.rfc3339(value)
74
+ when 'date' then Date.parse(value)
75
+ when 'date-time' then DateTime.parse(value)
76
+ else String(value)
77
+ end
78
+ when 'boolean' then %w(true false).include?(value.to_s) ? value : raise(ArgumentError)
79
+ else fail 'type is not valid' # TODO: handle this
80
+ end
81
+ rescue ArgumentError, TypeError => error
82
+ @errors << {
83
+ 'message' => "'#{value}' is not a valid #{param['type']}"
84
+ }
85
+ nil
86
+ rescue StandardError => error
87
+ fail error
88
+ nil
89
+ # TODO: handle
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,31 @@
1
+ module Swalidate
2
+ module Validator
3
+ class Main
4
+ attr_reader :endpoint_params, :request_params, :errors
5
+
6
+ def initialize(endpoint, request_params)
7
+ @endpoint_params = endpoint.parameters
8
+ @request_params = request_params
9
+ @errors = []
10
+ end
11
+
12
+ def call
13
+ # TODO: allow extra parameters?
14
+ endpoint_params.each do |param|
15
+ parameter = Swalidate::Validator::Parameter.new(param, request_params[param['name']])
16
+ if parameter.invalid?
17
+ @errors += parameter.errors
18
+ end
19
+ end
20
+ end
21
+
22
+ def valid?
23
+ errors.empty?
24
+ end
25
+
26
+ def invalid?
27
+ !valid?
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,43 @@
1
+ module Swalidate
2
+ module Validator
3
+ class Parameter
4
+ attr_reader :param, :value, :type
5
+
6
+ def initialize(param, value)
7
+ @param = param
8
+ @value = value
9
+ @type = Swalidate::Types::Main.new(param, value)
10
+ end
11
+
12
+ def valid?
13
+ return false if required? && !exists?
14
+
15
+ if exists?
16
+ type.valid?
17
+ else
18
+ !required?
19
+ end
20
+ end
21
+
22
+ def errors
23
+ if exists?
24
+ type.errors
25
+ else
26
+ required? ? ["'#{param['name']}' can't be blank."] : []
27
+ end
28
+ end
29
+
30
+ def invalid?
31
+ !valid?
32
+ end
33
+
34
+ def required?
35
+ param['required']
36
+ end
37
+
38
+ def exists?
39
+ !!value
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,3 +1,3 @@
1
1
  module Swalidate
2
- VERSION = "0.1.0"
2
+ VERSION = '0.1.1'.freeze
3
3
  end
data/lib/swalidate.rb CHANGED
@@ -1,4 +1,13 @@
1
- require "swalidate/version"
1
+ require 'forwardable'
2
+ require 'swagger'
3
+ require 'action_dispatch'
4
+ require 'swalidate/version'
5
+ require 'swalidate/schema'
6
+ require 'swalidate/endpoint'
7
+ require 'swalidate/types/main'
8
+ require 'swalidate/validator/parameter'
9
+ require 'swalidate/validator/main'
10
+ require 'swalidate/middleware'
2
11
 
3
12
  module Swalidate
4
13
  # Your code goes here...
Binary file
data/swalidate.gemspec CHANGED
@@ -4,15 +4,15 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'swalidate/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "swalidate"
7
+ spec.name = 'swalidate'
8
8
  spec.version = Swalidate::VERSION
9
- spec.authors = ["Furkan Ayhan"]
10
- spec.email = ["furkanayhn@gmail.com"]
9
+ spec.authors = ['Furkan Ayhan']
10
+ spec.email = ['furkanayhn@gmail.com']
11
11
 
12
- spec.summary = "Rack validation middleware using Swagger"
13
- spec.description = "Rack validation middleware using Swagger"
14
- spec.homepage = "https://github.com/furkanayhan/swalidate"
15
- spec.license = "MIT"
12
+ spec.summary = 'Rack validation middleware using Swagger'
13
+ spec.description = 'Rack validation middleware using Swagger'
14
+ spec.homepage = 'https://github.com/furkanayhan/swalidate'
15
+ spec.license = 'MIT'
16
16
 
17
17
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
18
  # to allow pushing to a single host or delete this section to allow pushing to any host.
@@ -26,11 +26,16 @@ Gem::Specification.new do |spec|
26
26
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
27
  f.match(%r{^(test|spec|features)/})
28
28
  end
29
- spec.bindir = "exe"
29
+ spec.bindir = 'exe'
30
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
- spec.require_paths = ["lib"]
31
+ spec.require_paths = ['lib']
32
32
 
33
- spec.add_development_dependency "bundler", "~> 1.14"
34
- spec.add_development_dependency "rake", "~> 10.0"
35
- spec.add_development_dependency "rspec", "~> 3.0"
33
+ spec.add_dependency 'actionpack'
34
+ spec.add_dependency 'swagger-core'
35
+
36
+ spec.add_development_dependency 'bundler', '~> 1.14'
37
+ spec.add_development_dependency 'rake', '~> 10.0'
38
+ spec.add_development_dependency 'rspec', '~> 3.0'
39
+ spec.add_development_dependency 'rubocop'
40
+ spec.add_development_dependency 'pry'
36
41
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swalidate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Furkan Ayhan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-26 00:00:00.000000000 Z
11
+ date: 2017-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: swagger-core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +80,34 @@ dependencies:
52
80
  - - "~>"
53
81
  - !ruby/object:Gem::Version
54
82
  version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
55
111
  description: Rack validation middleware using Swagger
56
112
  email:
57
113
  - furkanayhn@gmail.com
@@ -61,6 +117,7 @@ extra_rdoc_files: []
61
117
  files:
62
118
  - ".gitignore"
63
119
  - ".rspec"
120
+ - ".rubocop.yml"
64
121
  - ".travis.yml"
65
122
  - Gemfile
66
123
  - LICENSE.txt
@@ -69,7 +126,14 @@ files:
69
126
  - bin/console
70
127
  - bin/setup
71
128
  - lib/swalidate.rb
129
+ - lib/swalidate/endpoint.rb
130
+ - lib/swalidate/middleware.rb
131
+ - lib/swalidate/schema.rb
132
+ - lib/swalidate/types/main.rb
133
+ - lib/swalidate/validator/main.rb
134
+ - lib/swalidate/validator/parameter.rb
72
135
  - lib/swalidate/version.rb
136
+ - swalidate-0.1.0.gem
73
137
  - swalidate.gemspec
74
138
  homepage: https://github.com/furkanayhan/swalidate
75
139
  licenses: