jsonapi-validations 0.1.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 51f6ad7a9024b404c821d08302c1211fc8ab6d84
4
+ data.tar.gz: 814b58de2920226fbd45d6368a872e603b1c88d1
5
+ SHA512:
6
+ metadata.gz: c7155434543ebdc5165d090d236940fb6a07cecb384744fef8ececdecf48dd92c3a2a09bd8b09c3ba2376589aff88dc888c1a9dba6405b11f41b7a9191bba75a
7
+ data.tar.gz: 03fa3a140f3ea5ef289957542d15df92e2aabc74e861db885170bf42e95284a609ff6a4ec00b5709a36b2b11ca711acc3640bb7e7260766f117fa3ddcfb14d91
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # jsonapi-validations
2
+ Ruby gem for validating [JSON API](http://jsonapi.org) payloads.
3
+
4
+ ## Installation
5
+ ```ruby
6
+ # In Gemfile
7
+ gem 'jsonapi-validations'
8
+ ```
9
+ then
10
+ ```
11
+ $ bundle
12
+ ```
13
+ or manually via
14
+ ```
15
+ $ gem install jsonapi-validations
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ First, require the gem:
21
+ ```ruby
22
+ require 'jsonapi/validations'
23
+ ```
24
+ Then validate a resource creation/update payload:
25
+ ```ruby
26
+ params = {
27
+ permitted: {
28
+ id: true,
29
+ attributes: [:name, :address, :birthdate],
30
+ relationships: [:posts, :sponsor]
31
+ },
32
+ required: {
33
+ id: true,
34
+ attributes: [:name, :address],
35
+ relationships: [:sponsor]
36
+ },
37
+ types: {
38
+ primary: [:users, :admins],
39
+ relationships: {
40
+ posts: {
41
+ kind: :has_many,
42
+ types: [:blogs, :posts]
43
+ }
44
+ }
45
+ }
46
+ }
47
+ JSONAPI.validate_resource!(document_hash, params)
48
+ ```
49
+ or a relationship update payload:
50
+ ```ruby
51
+ params = {
52
+ kind: :has_many,
53
+ types: [:users, :admins]
54
+ }
55
+ JSONAPI.validate_relationship!(document_hash, params)
56
+ ```
57
+
58
+ ## License
59
+
60
+ jsonapi-validations is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -0,0 +1,11 @@
1
+ module JSONAPI
2
+ module_function
3
+
4
+ def validate_resource!(document, params = {})
5
+ Validations::Resource.validate!(document, params)
6
+ end
7
+
8
+ def validate_relationship!(document, params = {})
9
+ Validations::Relationship.validate!(document, params)
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ require 'jsonapi/parser'
2
+
3
+ module JSONAPI
4
+ module Validations
5
+ module Relationship
6
+ module_function
7
+
8
+ # Validate the types of related objects in a relationship update payload.
9
+ #
10
+ # @param [Hash] document The input JSONAPI document.
11
+ # @param [Hash] params Validation parameters.
12
+ # @option [Symbol] kind Whether it is a :has_many or :has_one.
13
+ # @option [Array<Symbol>] types Permitted types for the relationship.
14
+ # @raise [JSONAPI::Validator::InvalidDocument] if document is invalid.
15
+ def validate_relationship!(document, params = {})
16
+ JSONAPI.parse_relationship!(document)
17
+ validate_types!(document['data'], params[:types])
18
+ end
19
+
20
+ # @api private
21
+ def validate_types!(rel, rel_types, key = nil)
22
+ rel_name = key ? " #{key}" : ''
23
+ if rel_types[:kind] == :has_many
24
+ Document.ensure!(rel['data'].is_a?(Array),
25
+ "Expected relationship#{rel_name} to be has_many.")
26
+ return unless rel_types[:types]
27
+ rel['data'].each do |ri|
28
+ Document.ensure!(rel_types[:types].include?(ri['type'].to_sym),
29
+ "Type mismatch for relationship#{rel_name}: " \
30
+ "#{ri['type']} should be one of #{rel_types}")
31
+ end
32
+ else
33
+ return if rel['data'].nil?
34
+ Document.ensure!(rel['data'].is_a?(Hash),
35
+ "Expected relationship#{rel_name} to be has_one.")
36
+ return unless rel_types[:types]
37
+ ri = rel['data']
38
+ Document.ensure!(rel_types[:types].include?(ri['type'].to_sym),
39
+ "Type mismatch for relationship#{rel_name}: " \
40
+ "#{ri['type']} should be one of #{rel_types}")
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,118 @@
1
+ require 'jsonapi/parser'
2
+
3
+ module JSONAPI
4
+ module Validations
5
+ module Resource
6
+ module_function
7
+
8
+ # Validate the structure of a resource create/update payload. Optionally
9
+ # validate whitelisted/required id/attributes/relationships, as well as
10
+ # primary type and relationship types.
11
+ #
12
+ # @param [Hash] document The input JSONAPI document.
13
+ # @param [Hash] params Validation parameters.
14
+ # @option [Hash] permitted Permitted attributes/relationships/primary
15
+ # id. Optional. If not supplied, all legitimate fields are permitted.
16
+ # @option [Hash] required Required attributes/relationships/primary id.
17
+ # Optional. The fields must be explicitly permitted, or permitted
18
+ # should not be provided.
19
+ # @option [Hash] types Permitted primary/relationships types. Optional.
20
+ # The relationships must be explicitly permitted. Not all
21
+ # relationships' types have to be specified.
22
+ # @raise [JSONAPI::Validator::InvalidDocument] if document is invalid.
23
+ #
24
+ # @example
25
+ # params = {
26
+ # permitted: {
27
+ # id: true, # Simply ommit it to forbid it.
28
+ # attributes: [:title, :date],
29
+ # relationships: [:comments, :author]
30
+ # },
31
+ # required: {
32
+ # id: true,
33
+ # attributes: [:title],
34
+ # relationships: [:comments, :author]
35
+ # },
36
+ # types: {
37
+ # primary: [:posts],
38
+ # relationships: {
39
+ # comments: {
40
+ # kind: :has_many,
41
+ # types: [:comments]
42
+ # },
43
+ # author: {
44
+ # kind: :has_one,
45
+ # types: [:users, :superusers]
46
+ # }
47
+ # }
48
+ # }
49
+ # }
50
+ def validate!(document, params = {})
51
+ JSONAPI.parse_resource!(document)
52
+
53
+ validate_permitted!(document['data'], params[:permitted])
54
+ validate_required!(document['data'], params[:required])
55
+ validate_types!(document['data'], params[:types])
56
+ end
57
+
58
+ # @api private
59
+ def validate_permitted!(data, permitted)
60
+ return if permitted.nil?
61
+ Document.ensure!(permitted[:id] || !data.key?('id'),
62
+ 'Unpermitted id.')
63
+ # TODO(beauby): Handle meta (and possibly links) once the spec has
64
+ # been clarified.
65
+ permitted_attrs = permitted[:attributes] || []
66
+ if data.key?('attributes')
67
+ data['attributes'].keys.each do |attr|
68
+ Document.ensure!(permitted_attrs.include?(attr.to_sym),
69
+ "Unpermitted attribute #{attr}")
70
+ end
71
+ end
72
+ permitted_rels = permitted[:relationships] || []
73
+ if data.key?('relationships')
74
+ data['relationships'].keys.each do |rel|
75
+ Document.ensure!(permitted_rels.include?(rel.to_sym))
76
+ end
77
+ end
78
+ end
79
+
80
+ # @api private
81
+ def validate_required!(data, required)
82
+ return if required.nil?
83
+ Document.ensure!(data.key?('id') || !required[:id],
84
+ 'Missing required id.')
85
+ # TODO(beauby): Same as for permitted.
86
+
87
+ Document.ensure!(data.key?('attributes') || !required[:attributes],
88
+ 'Missing required attributes.')
89
+ required[:attributes].each do |attr|
90
+ Document.ensure!(data['attributes'][attr.to_s],
91
+ "Missing required attribute #{attr}.")
92
+ end
93
+ Document.ensure!(data.key?('relationships') ||
94
+ !required[:relationships],
95
+ 'Missing required relationships.')
96
+ required[:relationships].each do |rel|
97
+ Document.ensure!(data['relationships'][rel.to_s],
98
+ "Missing required relationship #{rel}.")
99
+ end
100
+ end
101
+
102
+ # @api private
103
+ def validate_types!(data, types)
104
+ return if types.nil?
105
+ Document.ensure!(!types[:primary] ||
106
+ types[:primary].include?(data['type'].to_sym),
107
+ "Type mismatch for resource: #{data['type']} " \
108
+ "should be one of #{types[:primary]}")
109
+ return unless data.key?('relationships') && types.key?(:relationships)
110
+ types[:relationships].each do |key, rel_types|
111
+ rel = data['relationships'][key.to_s]
112
+ next unless rel
113
+ Relationship.validate_types!(rel, rel_types, key)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsonapi-validations
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1.beta1
5
+ platform: ruby
6
+ authors:
7
+ - Lucas Hosseini
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jsonapi-parser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.1'
27
+ description: Validate presence/absence of resource creation/update and relationship
28
+ update payloads, as well as types related resources
29
+ email: lucas.hosseini@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - README.md
35
+ - lib/jsonapi/validations.rb
36
+ - lib/jsonapi/validations/relationship.rb
37
+ - lib/jsonapi/validations/resource.rb
38
+ homepage: https://github.com/beauby/jsonapi-validations
39
+ licenses:
40
+ - MIT
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">"
54
+ - !ruby/object:Gem::Version
55
+ version: 1.3.1
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 2.5.1
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: Validate JSONAPI payloads.
62
+ test_files: []