easy-jsonapi 1.0.0

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