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
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/core/rake_task'
4
+ require 'yard'
5
+
6
+ task default: %i[test build document]
7
+
8
+ RSpec::Core::RakeTask.new(:test) do |t|
9
+ t.verbose = false
10
+ end
11
+
12
+ task :build do
13
+ system('gem build easy-jsonapi.gemspec')
14
+ end
15
+
16
+ YARD::Rake::YardocTask.new(:document) do |t|
17
+ t.files = ['lib/**/*.rb'] # optional
18
+ t.options = ['--title', "YARD #{YARD::VERSION} Documentation", '--markup=markdown'] # optional
19
+ t.stats_options = ['--list-undoc'] # optional
20
+ end
@@ -0,0 +1,74 @@
1
+ <!--
2
+ # @markup markdown
3
+ # @title AccessingPartsOfTheRequest
4
+ -->
5
+
6
+ # Accessing Different Parts of The Request
7
+
8
+ ```ruby
9
+ j_req = JSONAPI::Parser.parse(env)
10
+ ```
11
+
12
+ ## Quick Access Methods
13
+
14
+ ```ruby
15
+ j_req.path # Gives path info
16
+ j_req.http_method # GET, POST, PUT, etc
17
+ j_req.host # localhost
18
+ j_req.port # 8080
19
+ j_req.query_string # query string
20
+ ```
21
+
22
+ ## Accessing the Query Params
23
+
24
+ ```ruby
25
+ j_req.params # returns enumerable JSONAPI::Request::QueryParamCollection
26
+
27
+ q_param = JSONAPI::Request::QueryParamCollection::QueryParam.new 'new_name' 'value'
28
+ j_req.params.add(q_param) # add a query param to the collection
29
+ j_req.params.get('new_name') # get param
30
+ j_req.params.new_name # dynamically get param
31
+ j_req.params.remove('new_name') # remove header
32
+ j_req.params.to_h # { new_name: ['value'] }
33
+
34
+ # given ?include=author,comments&filter[author]=name&sort=alpha
35
+ j_req.params.includes # includes
36
+ j_req.paras.filters # resource filters
37
+ j_req.params.sorts # resource ordering
38
+ j_req.params.page # page / offset
39
+ j_req.params.fields # sparse fieldsets
40
+ j_req.params.to_s # include=author,comments&filter[name]=test&new_name=new_val
41
+ ```
42
+
43
+ ## Accessing the Headers
44
+
45
+ ```ruby
46
+ j_req.headers # returns enumerable JSONAPI::HeaderCollection
47
+
48
+ h = JSONAPI::HeaderCollection::Header.new 'Content-Type', 'text/html'
49
+ j_req.headers.add(h)
50
+ j_req.headers.get('content-type') # retrieves header
51
+ j_req.headers.content_type # dynamically retrieves header
52
+ j_req.headers.remove('content-type') # remove header
53
+ j_req.headers.to_h # { CONTENT_TYPE: 'text/html' }
54
+ j_req.headers.to_s # (JSON compliant) { "CONTENT_TYPE": "text/html" }
55
+ ```
56
+
57
+ ## Accessing the Request Body
58
+
59
+ ```ruby
60
+ j_req.body # returns JSONAPI::Document
61
+
62
+ j_req.body.data # The JSONAPI data member
63
+ j_req.body.meta # The JSONAPI meta member
64
+ j_req.body.links # The JSONAPI links member
65
+ j_req.body.included # The JSONAPI included member
66
+ j_req.body.errors # The JSONAPI errors member
67
+ j_req.body.jsonapi # The JSONAPI jsonapi member
68
+
69
+ j_req.body.to_s # serialized JSONAPI
70
+ j_req.body.to_h # ruby hash representation of JSONAPI
71
+
72
+ # NOTE: j_req.body.data returns a resoure or an array of resources depending on the request
73
+ j_req.body.data # JSONAPI::Document::Resource or [JSONAPI::Document::Resource]
74
+ ```
@@ -0,0 +1,95 @@
1
+ <!--
2
+ # @markup markdown
3
+ # @title UserConfigurations
4
+ -->
5
+
6
+ # Configuring the Middleware
7
+
8
+ ## Quick Start
9
+
10
+ To add custom checks to the middleware, modify a Config object and pass it to the Config Manager.
11
+
12
+ The Config Manager is accessible through a block passed to the middleware upon initialization.
13
+
14
+ ```ruby
15
+ use JSONAPI::Middleware do |config_manager|
16
+ # ...
17
+ end
18
+ ```
19
+
20
+ To add restrictions to ALL requests use default global config included with the Config Manager:
21
+
22
+ ```ruby
23
+ use JSONAPI::Middleware do |config_manager|
24
+ config_manager.global.allow_client_ids = true
25
+ end
26
+ ```
27
+
28
+ To set up a restrictions for a specific resource type, create and configure a new Config object and add it to the Config Manager:
29
+
30
+ ```ruby
31
+ use JSONAPI::Middleware do |config_manager|
32
+ config = JSONAPI::ConfigManager::Config.new
33
+ config.allow_client_ids = true
34
+ config_manager[:person] = config
35
+ end
36
+ ```
37
+
38
+ ## Available Config Options
39
+
40
+ ### Document Checking Customization
41
+
42
+ To specify required members in a document, create a hash in the structure of the expected JSON document, and list required members as nil. Members that are not required do not have to be listed.
43
+
44
+ ```ruby
45
+ config.required_document_members =
46
+ {
47
+ data: {
48
+ attributes: {
49
+ this_is_required: nil
50
+ }
51
+ },
52
+ meta: nil
53
+ }
54
+ ```
55
+
56
+ You can go even further by adding a proc instead of nil to provide a custom way of determining whether a value (and request) is valid.
57
+
58
+ ```ruby
59
+ config.required_document_members =
60
+ {
61
+ data: {
62
+ attributes: {
63
+ this_is_required: proc { |value| ['im_allowed', 'me_too', 'also_me'].include?(value) }
64
+ }
65
+ },
66
+ meta: proc { |value_hash| value_hash.keys?(:count) }
67
+ }
68
+ ```
69
+
70
+ To allow for client generated ids, set the method to true.
71
+
72
+ ```ruby
73
+ config.allow_client_ids = true
74
+ ```
75
+
76
+ ### Header Checking Customization
77
+
78
+ Specify a list of required headers:
79
+
80
+ ```ruby
81
+ config.required_headers = %w[content-type xxx-authentication]
82
+ ```
83
+
84
+ ### Query Param Customization
85
+
86
+ Specify a list of required query params:
87
+
88
+ ```ruby
89
+ config.required_query_params =
90
+ {
91
+ fields: { people: nil },
92
+ include: nil,
93
+ custom_param: nil
94
+ }
95
+ ```
data/bin/bundle ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../../Gemfile", __FILE__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_version
64
+ @bundler_version ||=
65
+ env_var_version || cli_arg_version ||
66
+ lockfile_version
67
+ end
68
+
69
+ def bundler_requirement
70
+ return "#{Gem::Requirement.default}.a" unless bundler_version
71
+
72
+ bundler_gem_version = Gem::Version.new(bundler_version)
73
+
74
+ requirement = bundler_gem_version.approximate_recommendation
75
+
76
+ return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0")
77
+
78
+ requirement += ".a" if bundler_gem_version.prerelease?
79
+
80
+ requirement
81
+ end
82
+
83
+ def load_bundler!
84
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
85
+
86
+ activate_bundler
87
+ end
88
+
89
+ def activate_bundler
90
+ gem_error = activation_error_handling do
91
+ gem "bundler", bundler_requirement
92
+ end
93
+ return if gem_error.nil?
94
+ require_error = activation_error_handling do
95
+ require "bundler/version"
96
+ end
97
+ return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
98
+ warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
99
+ exit 42
100
+ end
101
+
102
+ def activation_error_handling
103
+ yield
104
+ nil
105
+ rescue StandardError, LoadError => e
106
+ e
107
+ end
108
+ end
109
+
110
+ m.load_bundler!
111
+
112
+ if m.invoked_as_script?
113
+ load Gem.bin_path("bundler", "bundle")
114
+ end
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'easy-jsonapi'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/htmldiff ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'htmldiff' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("diff-lcs", "htmldiff")
data/bin/kramdown ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'kramdown' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("kramdown", "kramdown")
data/bin/ldiff ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'ldiff' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("diff-lcs", "ldiff")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'license_finder' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("license_finder", "license_finder")