easy-jsonapi 1.0.0

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 (91) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/publish-gem.yml +60 -0
  3. data/.github/workflows/rake.yml +35 -0
  4. data/.rspec +3 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +5 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +5 -0
  9. data/Gemfile.lock +106 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +209 -0
  12. data/Rakefile +20 -0
  13. data/UsingTheRequestObject.md +74 -0
  14. data/UsingUserConfigurations.md +95 -0
  15. data/bin/bundle +114 -0
  16. data/bin/console +15 -0
  17. data/bin/htmldiff +29 -0
  18. data/bin/kramdown +29 -0
  19. data/bin/ldiff +29 -0
  20. data/bin/license_finder +29 -0
  21. data/bin/license_finder_pip.py +29 -0
  22. data/bin/maruku +29 -0
  23. data/bin/marutex +29 -0
  24. data/bin/nokogiri +29 -0
  25. data/bin/racc +29 -0
  26. data/bin/rackup +29 -0
  27. data/bin/rake +29 -0
  28. data/bin/redcarpet +29 -0
  29. data/bin/reverse_markdown +29 -0
  30. data/bin/rspec +29 -0
  31. data/bin/rubocop +29 -0
  32. data/bin/ruby-parse +29 -0
  33. data/bin/ruby-rewrite +29 -0
  34. data/bin/setup +8 -0
  35. data/bin/solargraph +29 -0
  36. data/bin/thor +29 -0
  37. data/bin/tilt +29 -0
  38. data/bin/yard +29 -0
  39. data/bin/yardoc +29 -0
  40. data/bin/yri +29 -0
  41. data/easy-jsonapi.gemspec +39 -0
  42. data/lib/easy/jsonapi.rb +12 -0
  43. data/lib/easy/jsonapi/collection.rb +144 -0
  44. data/lib/easy/jsonapi/config_manager.rb +144 -0
  45. data/lib/easy/jsonapi/config_manager/config.rb +49 -0
  46. data/lib/easy/jsonapi/document.rb +71 -0
  47. data/lib/easy/jsonapi/document/error.rb +48 -0
  48. data/lib/easy/jsonapi/document/error/error_member.rb +15 -0
  49. data/lib/easy/jsonapi/document/jsonapi.rb +26 -0
  50. data/lib/easy/jsonapi/document/jsonapi/jsonapi_member.rb +15 -0
  51. data/lib/easy/jsonapi/document/links.rb +36 -0
  52. data/lib/easy/jsonapi/document/links/link.rb +15 -0
  53. data/lib/easy/jsonapi/document/meta.rb +26 -0
  54. data/lib/easy/jsonapi/document/meta/meta_member.rb +14 -0
  55. data/lib/easy/jsonapi/document/resource.rb +56 -0
  56. data/lib/easy/jsonapi/document/resource/attributes.rb +37 -0
  57. data/lib/easy/jsonapi/document/resource/attributes/attribute.rb +29 -0
  58. data/lib/easy/jsonapi/document/resource/relationships.rb +40 -0
  59. data/lib/easy/jsonapi/document/resource/relationships/relationship.rb +50 -0
  60. data/lib/easy/jsonapi/document/resource_id.rb +28 -0
  61. data/lib/easy/jsonapi/exceptions.rb +27 -0
  62. data/lib/easy/jsonapi/exceptions/document_exceptions.rb +619 -0
  63. data/lib/easy/jsonapi/exceptions/headers_exceptions.rb +156 -0
  64. data/lib/easy/jsonapi/exceptions/naming_exceptions.rb +36 -0
  65. data/lib/easy/jsonapi/exceptions/query_params_exceptions.rb +67 -0
  66. data/lib/easy/jsonapi/exceptions/user_defined_exceptions.rb +253 -0
  67. data/lib/easy/jsonapi/field.rb +43 -0
  68. data/lib/easy/jsonapi/header_collection.rb +38 -0
  69. data/lib/easy/jsonapi/header_collection/header.rb +11 -0
  70. data/lib/easy/jsonapi/item.rb +88 -0
  71. data/lib/easy/jsonapi/middleware.rb +158 -0
  72. data/lib/easy/jsonapi/name_value_pair.rb +72 -0
  73. data/lib/easy/jsonapi/name_value_pair_collection.rb +78 -0
  74. data/lib/easy/jsonapi/parser.rb +38 -0
  75. data/lib/easy/jsonapi/parser/document_parser.rb +196 -0
  76. data/lib/easy/jsonapi/parser/headers_parser.rb +33 -0
  77. data/lib/easy/jsonapi/parser/rack_req_params_parser.rb +117 -0
  78. data/lib/easy/jsonapi/request.rb +40 -0
  79. data/lib/easy/jsonapi/request/query_param_collection.rb +56 -0
  80. data/lib/easy/jsonapi/request/query_param_collection/fields_param.rb +32 -0
  81. data/lib/easy/jsonapi/request/query_param_collection/fields_param/fieldset.rb +34 -0
  82. data/lib/easy/jsonapi/request/query_param_collection/filter_param.rb +28 -0
  83. data/lib/easy/jsonapi/request/query_param_collection/filter_param/filter.rb +34 -0
  84. data/lib/easy/jsonapi/request/query_param_collection/include_param.rb +119 -0
  85. data/lib/easy/jsonapi/request/query_param_collection/page_param.rb +55 -0
  86. data/lib/easy/jsonapi/request/query_param_collection/query_param.rb +47 -0
  87. data/lib/easy/jsonapi/request/query_param_collection/sort_param.rb +25 -0
  88. data/lib/easy/jsonapi/response.rb +22 -0
  89. data/lib/easy/jsonapi/utility.rb +158 -0
  90. data/lib/easy/jsonapi/version.rb +8 -0
  91. metadata +248 -0
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONAPI
4
+ class ConfigManager
5
+
6
+ # User configurations for the gem
7
+ class Config
8
+
9
+ attr_reader :required_document_members, :required_headers, :required_query_params,
10
+ :allow_client_ids
11
+
12
+ def initialize
13
+ @allow_client_ids = false
14
+ @default = true
15
+ end
16
+
17
+ # Performancewise, configs are all initialized as a startup cost, to change them you need to
18
+ # restart the server. As a result of this, the #default? is used to process a request
19
+ # faster if user-defined configs do not need to be checked when screening http requests.
20
+ # Because @default is set to false upon config assignment (see #method missing in Config),
21
+ # this allows the a user to potentially make the middleware screening less performant than necessary
22
+ # by assigning config values to the default values, or assigning values to something not default,
23
+ # and then assigning config values to the default again. If used as intended, however, this should make
24
+ # the middleware screening faster.
25
+ # @return [TrueClass | FalseClass]
26
+ def default?
27
+ @default
28
+ end
29
+
30
+ private
31
+
32
+ READER_METHODS = %i[required_document_members required_headers required_query_params allow_client_ids].freeze
33
+
34
+ # Only used if implementing Item directly.
35
+ # dynamically creates accessor methods for instance variables
36
+ # created in the initialize
37
+ def method_missing(method_name, *args, &block)
38
+ super unless READER_METHODS.include?(method_name.to_s[..-2].to_sym)
39
+ instance_variable_set("@#{method_name}"[..-2].to_sym, args[0])
40
+ @default = false
41
+ end
42
+
43
+ # Needed when using #method_missing
44
+ def respond_to_missing?(method_name, *args)
45
+ methods.include?(method_name) || super
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # classes extending document: (require needed because parser requires document)
4
+ require 'easy/jsonapi/document/resource'
5
+ require 'easy/jsonapi/document/resource_id'
6
+ require 'easy/jsonapi/document/error'
7
+ require 'easy/jsonapi/document/jsonapi'
8
+ require 'easy/jsonapi/document/links'
9
+ require 'easy/jsonapi/document/meta'
10
+
11
+ require 'easy/jsonapi/utility'
12
+ require 'easy/jsonapi/exceptions/document_exceptions'
13
+
14
+ module JSONAPI
15
+
16
+ # Contains all objects relating to a JSONAPI Document
17
+ class Document
18
+
19
+ attr_reader :data, :meta, :links, :included, :errors, :jsonapi
20
+
21
+ # @param document [Hash] A hash of the different possible document members
22
+ # with the values being clases associated with those members
23
+ # @data is either a JSONAPI::Document::Resource or a Array<JSONAPI::Document::Resource>
24
+ # or a JSONAPI::Document::ResourceId or a Array<JSONAPI::Document::ResourceId>
25
+ # @meta is JSONAPI::Document::Meta
26
+ # @links is JSONAPI::Document::Links
27
+ # @included is an Array<JSONAPI::Document::Resource>
28
+ # @errors is an Array<JSONAPI::Document::Error>
29
+ # @jsonapi is JSONAPI::Document::Jsonapi
30
+ # @raise RuntimeError A document must be initialized with a hash of its members.
31
+ def initialize(document = {})
32
+ raise 'JSONAPI::Document parameter must be a Hash' unless document.is_a? Hash
33
+ @data = document[:data]
34
+ @meta = document[:meta]
35
+ @links = document[:links] # software generated?
36
+ @included = document[:included]
37
+ @errors = document[:errors]
38
+ @jsonapi = document[:jsonapi] # online documentation
39
+ end
40
+
41
+ # Represent as a string mimicing the JSONAPI format
42
+ def to_s
43
+ '{ ' \
44
+ "#{JSONAPI::Utility.member_to_s('data', @data, first_member: true)}" \
45
+ "#{JSONAPI::Utility.member_to_s('meta', @meta)}" \
46
+ "#{JSONAPI::Utility.member_to_s('links', @links)}" \
47
+ "#{JSONAPI::Utility.member_to_s('included', @included)}" \
48
+ "#{JSONAPI::Utility.member_to_s('errors', @errors)}" \
49
+ "#{JSONAPI::Utility.member_to_s('jsonapi', @jsonapi)}" \
50
+ ' }'
51
+ end
52
+
53
+ # Represent as a hash mimicing the JSONAPI format
54
+ def to_h
55
+ to_return = {}
56
+ JSONAPI::Utility.to_h_member(to_return, @data, :data)
57
+ JSONAPI::Utility.to_h_member(to_return, @meta, :meta)
58
+ JSONAPI::Utility.to_h_member(to_return, @links, :links)
59
+ JSONAPI::Utility.to_h_member(to_return, @included, :included)
60
+ JSONAPI::Utility.to_h_member(to_return, @errors, :errors)
61
+ JSONAPI::Utility.to_h_member(to_return, @jsonapi, :jsonapi)
62
+ to_return
63
+ end
64
+
65
+ # Check if the document is JSONAPI compliant
66
+ # @raise If the document's to_h does not comply
67
+ def validate
68
+ JSONAPI::Exceptions::DocumentExceptions.check_compliance(to_h)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/name_value_pair_collection'
4
+ require 'easy/jsonapi/document/error/error_member' # extension
5
+ require 'easy/jsonapi/utility'
6
+
7
+ module JSONAPI
8
+ class Document
9
+ # An individual errors member in a jsonapi's document top level 'errors' member array
10
+ class Error < JSONAPI::NameValuePairCollection
11
+
12
+ # @param err_members [Array<JSONAPI::Document::Error::ErrorMember>]
13
+ # The error members that belong to this specific error.
14
+ def initialize(err_members = [])
15
+ super(err_members, item_type: JSONAPI::Document::Error::ErrorMember)
16
+ end
17
+
18
+ # #empyt? provided by super
19
+ # #include provided by super
20
+
21
+ # Add a error to the collection using it's name
22
+ # @param error_mem [JSONAPI::Document::Error::ErrorMember]
23
+ def add(error_mem)
24
+ super(error_mem, &:name)
25
+ end
26
+
27
+ # Another way to call add
28
+ # @param (see #add)
29
+ def <<(error_mem)
30
+ super(error_mem, &:name)
31
+ end
32
+
33
+ # #<< provided by super, but calls overriden #add
34
+ # #each provided from super
35
+ # #remove provided from super
36
+ # #get provided by super
37
+ # #keys provided by super
38
+ # #size provided by super
39
+ # #to_s provided by super
40
+
41
+ # Represent an Error as a hash
42
+ def to_h
43
+ JSONAPI::Utility.to_h_collection(self)
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/name_value_pair'
4
+ require 'easy/jsonapi/document/error'
5
+
6
+ module JSONAPI
7
+ class Document
8
+ class Error < JSONAPI::NameValuePairCollection
9
+
10
+ # An individual error member
11
+ class ErrorMember < JSONAPI::NameValuePair
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/name_value_pair_collection'
4
+ require 'easy/jsonapi/document/jsonapi/jsonapi_member' # extension
5
+
6
+ module JSONAPI
7
+ class Document
8
+
9
+ # The jsonapi top level member of a JSON:API document
10
+ class Jsonapi < JSONAPI::NameValuePairCollection
11
+
12
+ # @param jsonapi_member_arr [Array<JSONAPI::Document::Jsonapi::JsonapiMember] The collection
13
+ # of members to intialize this collection with.
14
+ def initialize(jsonapi_member_arr = [])
15
+ super(jsonapi_member_arr, item_type: JSONAPI::Document::Jsonapi::JsonapiMember)
16
+ end
17
+
18
+ # Add a jsonapi member to the collection
19
+ # @param jsonapi_member [JSONAPI::Document::Jsonapi::JsonapiMember] The member to add
20
+ def add(jsonapi_member)
21
+ super(jsonapi_member, &:name)
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/name_value_pair'
4
+ require 'easy/jsonapi/document/jsonapi'
5
+
6
+ module JSONAPI
7
+ class Document
8
+ class Jsonapi < JSONAPI::NameValuePairCollection
9
+
10
+ # An individual member in a JSON:API Meta object
11
+ class JsonapiMember < JSONAPI::NameValuePair
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/name_value_pair_collection'
4
+ require 'easy/jsonapi/document/links/link' # extension
5
+ require 'easy/jsonapi/utility'
6
+
7
+ module JSONAPI
8
+ class Document
9
+
10
+ # The links of a resource
11
+ class Links < JSONAPI::NameValuePairCollection
12
+
13
+ # @param link_arr [Array<JSONAPI::Document::Links::Link] The array
14
+ # of links to initialize this collection with.
15
+ def initialize(link_arr = [])
16
+ super(link_arr, item_type: JSONAPI::Document::Links::Link)
17
+ end
18
+
19
+ # Add a jsonapi member to the collection
20
+ # @param link [JSONAPI::Document::Links:Link] The member to add
21
+ def add(link)
22
+ super(link, &:name)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ # #empyt? provided by super class
29
+ # #include provided by super class
30
+ # #add provided by super
31
+ # #each provided from super class
32
+ # #remove provided from super class
33
+ # #get provided by super class
34
+ # #keys provided by super class
35
+ # #size provided by super class
36
+ # #to_s provided from super class
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/name_value_pair'
4
+ require 'easy/jsonapi/document/links'
5
+
6
+ module JSONAPI
7
+ class Document
8
+ class Links < JSONAPI::NameValuePairCollection
9
+
10
+ # An individual attribute in a JSON:API Links object
11
+ class Link < JSONAPI::NameValuePair
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/name_value_pair_collection'
4
+ require 'easy/jsonapi/document/meta/meta_member' # extension
5
+
6
+ module JSONAPI
7
+ class Document
8
+
9
+ # The meta of a resource
10
+ class Meta < JSONAPI::NameValuePairCollection
11
+
12
+ # @param meta_arr [Array<JSONAPI::Document::Meta::MetaMember] The
13
+ # array of meta members to initialize the collection with
14
+ def initialize(meta_arr = [])
15
+ meta_arr = [meta_arr] unless meta_arr.is_a? Array
16
+ super(meta_arr, item_type: JSONAPI::Document::Meta::MetaMember)
17
+ end
18
+
19
+ # Add a jsonapi member to the collection
20
+ # @param meta_member [JSONAPI::Document::Meta::MetaMember] The member to add
21
+ def add(meta_member)
22
+ super(meta_member, &:name)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/document/meta'
4
+
5
+ module JSONAPI
6
+ class Document
7
+ class Meta < JSONAPI::NameValuePairCollection
8
+
9
+ # An individual member in a JSON:API Meta object
10
+ class MetaMember < JSONAPI::NameValuePair
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/document/resource/attributes' # extension
4
+ require 'easy/jsonapi/document/resource/relationships' # extension
5
+ require 'easy/jsonapi/utility'
6
+
7
+ module JSONAPI
8
+ class Document
9
+ # A jsonapi resource object
10
+ class Resource
11
+
12
+ attr_accessor :attributes, :relationships, :links, :meta, :type, :id
13
+
14
+ # @param members_hash [Hash] The members to initialize a resource with
15
+ def initialize(members_hash)
16
+ unless members_hash.is_a? Hash
17
+ raise 'A JSONAPI::Document::Resource must be initialized with a Hash'
18
+ end
19
+ @type = members_hash[:type].to_s unless members_hash[:type].nil?
20
+ @id = members_hash[:id].to_s unless members_hash[:id].nil?
21
+ @attributes = members_hash[:attributes]
22
+ @relationships = members_hash[:relationships]
23
+ @links = members_hash[:links]
24
+ @meta = members_hash[:meta]
25
+ end
26
+
27
+ # String representation of Document that is JSON parsable
28
+ # If any document memeber is nil, it does not include it
29
+ # in the returned string.
30
+ # @return [String] The string representation of a JSONAPI Document
31
+ def to_s
32
+ '{ ' \
33
+ "#{JSONAPI::Utility.member_to_s('type', @type, first_member: true)}" \
34
+ "#{JSONAPI::Utility.member_to_s('id', @id)}" \
35
+ "#{JSONAPI::Utility.member_to_s('attributes', @attributes)}" \
36
+ "#{JSONAPI::Utility.member_to_s('relationships', @relationships)}" \
37
+ "#{JSONAPI::Utility.member_to_s('links', @links)}" \
38
+ "#{JSONAPI::Utility.member_to_s('meta', @meta)}" \
39
+ ' }'
40
+ end
41
+
42
+ # Hash representation of a jsonapi resource
43
+ # @return [Hash] The jsonapi representation of the resource
44
+ def to_h
45
+ to_return = {}
46
+ JSONAPI::Utility.to_h_member(to_return, @type, :type)
47
+ JSONAPI::Utility.to_h_member(to_return, @id, :id)
48
+ JSONAPI::Utility.to_h_member(to_return, @attributes, :attributes)
49
+ JSONAPI::Utility.to_h_member(to_return, @relationships, :relationships)
50
+ JSONAPI::Utility.to_h_member(to_return, @links, :links)
51
+ JSONAPI::Utility.to_h_member(to_return, @meta, :meta)
52
+ to_return
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/name_value_pair_collection'
4
+ require 'easy/jsonapi/document/resource/attributes/attribute'
5
+
6
+ module JSONAPI
7
+ class Document
8
+ class Resource
9
+ # The attributes of a resource
10
+ class Attributes < JSONAPI::NameValuePairCollection
11
+
12
+ # @param attr_arr [Array<JSONAPI::Document::Resource::Attributes::Attribute]
13
+ # The collection of attributes to initialize the collection with.
14
+ def initialize(attr_arr = [])
15
+ super(attr_arr, item_type: JSONAPI::Document::Resource::Attributes::Attribute)
16
+ end
17
+
18
+ # Add a jsonapi member to the collection
19
+ # @param attribute [JSONAPI::Document::Resource::Attributes::Attribute] The member to add
20
+ def add(attribute)
21
+ super(attribute, &:name)
22
+ end
23
+
24
+ # #empyt? provided by super
25
+ # #include provided by super
26
+ # #add provided by super
27
+ # #each provided from super
28
+ # #remove provided from super
29
+ # #get provided by super
30
+ # #keys provided by super
31
+ # #size provided by super
32
+
33
+ # to_s provided from super
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easy/jsonapi/field'
4
+ require 'easy/jsonapi/document/resource/attributes'
5
+ require 'easy/jsonapi/name_value_pair'
6
+
7
+ module JSONAPI
8
+ class Document
9
+ class Resource
10
+ class Attributes < JSONAPI::NameValuePairCollection
11
+
12
+ # An individual attribute in a JSON:API Attributes object
13
+ class Attribute < JSONAPI::NameValuePair
14
+
15
+ attr_reader :field
16
+
17
+ # @param name [String] The name of an attribute
18
+ # @param value [String] The value of an attribute
19
+ # @param type [Any] The type of an attribute value
20
+ def initialize(name, value, type: String)
21
+ @field = JSONAPI::Field.new(name, type: type)
22
+ super(name, value)
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end