jsonapi-realizer 4.4.0 → 5.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -104
  3. data/lib/jsonapi/realizer.rb +26 -25
  4. data/lib/jsonapi/realizer/action.rb +2 -2
  5. data/lib/jsonapi/realizer/adapter.rb +21 -58
  6. data/lib/jsonapi/realizer/adapter/active_record.rb +38 -17
  7. data/lib/jsonapi/realizer/adapter_spec.rb +3 -2
  8. data/lib/jsonapi/realizer/configuration.rb +22 -0
  9. data/lib/jsonapi/realizer/context.rb +8 -0
  10. data/lib/jsonapi/realizer/controller.rb +55 -0
  11. data/lib/jsonapi/realizer/error.rb +10 -9
  12. data/lib/jsonapi/realizer/error/invalid_content_type_header.rb +5 -0
  13. data/lib/jsonapi/realizer/error/invalid_data_type_property.rb +13 -0
  14. data/lib/jsonapi/realizer/error/invalid_root_property.rb +13 -0
  15. data/lib/jsonapi/realizer/error/{duplicate_registration.rb → missing_data_type_property.rb} +1 -1
  16. data/lib/jsonapi/realizer/error/resource_attribute_not_found.rb +14 -0
  17. data/lib/jsonapi/realizer/error/resource_relationship_not_found.rb +14 -0
  18. data/lib/jsonapi/realizer/resource.rb +278 -73
  19. data/lib/jsonapi/realizer/resource/attribute.rb +23 -0
  20. data/lib/jsonapi/realizer/resource/configuration.rb +27 -0
  21. data/lib/jsonapi/realizer/resource/relation.rb +31 -0
  22. data/lib/jsonapi/realizer/resource_spec.rb +55 -8
  23. data/lib/jsonapi/realizer/version.rb +1 -1
  24. data/lib/jsonapi/realizer_spec.rb +22 -119
  25. metadata +70 -20
  26. data/lib/jsonapi/realizer/action/create.rb +0 -36
  27. data/lib/jsonapi/realizer/action/create_spec.rb +0 -165
  28. data/lib/jsonapi/realizer/action/destroy.rb +0 -27
  29. data/lib/jsonapi/realizer/action/destroy_spec.rb +0 -81
  30. data/lib/jsonapi/realizer/action/index.rb +0 -29
  31. data/lib/jsonapi/realizer/action/index_spec.rb +0 -75
  32. data/lib/jsonapi/realizer/action/show.rb +0 -35
  33. data/lib/jsonapi/realizer/action/show_spec.rb +0 -81
  34. data/lib/jsonapi/realizer/action/update.rb +0 -37
  35. data/lib/jsonapi/realizer/action/update_spec.rb +0 -170
  36. data/lib/jsonapi/realizer/action_spec.rb +0 -46
  37. data/lib/jsonapi/realizer/adapter/memory.rb +0 -31
  38. data/lib/jsonapi/realizer/error/invalid_accept_header.rb +0 -9
  39. data/lib/jsonapi/realizer/error/malformed_data_root_property.rb +0 -9
  40. data/lib/jsonapi/realizer/error/missing_accept_header.rb +0 -9
  41. data/lib/jsonapi/realizer/error/missing_type_resource_property.rb +0 -9
@@ -1,81 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe JSONAPI::Realizer::Action::Show do
4
- let(:action) { described_class.new(payload: payload, headers: headers, type: :photos) }
5
-
6
- describe "#model" do
7
- subject { action.model }
8
-
9
- context "with no top-level data and good content-type header no accept headers" do
10
- let(:payload) do
11
- {}
12
- end
13
- let(:headers) do
14
- {
15
- "Content-Type" => "application/vnd.api+json",
16
- }
17
- end
18
-
19
- it "raises an exception" do
20
- expect {subject}.to raise_exception(JSONAPI::Realizer::Error::MissingAcceptHeader)
21
- end
22
- end
23
-
24
- context "with no top-level data and good content-type header and wrong accept header" do
25
- let(:payload) do
26
- {}
27
- end
28
- let(:headers) do
29
- {
30
- "Content-Type" => "application/vnd.api+json",
31
- "Accept" => "application/json"
32
- }
33
- end
34
-
35
- it "raises an exception" do
36
- expect {subject}.to raise_exception(JSONAPI::Realizer::Error::InvalidAcceptHeader)
37
- end
38
- end
39
-
40
- context "with a good payload and good headers" do
41
- let(:payload) do
42
- {
43
- "id" => "d09ae4c6-0fc3-4c42-8fe8-6029530c3bed"
44
- }
45
- end
46
- let(:headers) do
47
- {
48
- "Content-Type" => "application/vnd.api+json",
49
- "Accept" => "application/vnd.api+json"
50
- }
51
- end
52
-
53
- shared_examples "api" do
54
- it "returns a photo model" do
55
- expect(subject).to be_a_kind_of(Photo)
56
- end
57
-
58
- it "returns the photos attributes" do
59
- expect(subject).to have_attributes(title: "Ember Fox", src: "http://example.com/images/productivity-2.png")
60
- end
61
- end
62
-
63
- context "in a memory store", memory: true do
64
- before do
65
- Photo::STORE["550e8400-e29b-41d4-a716-446655440000"] = {
66
- id: "550e8400-e29b-41d4-a716-446655440000",
67
- title: "Ember Hamster",
68
- src: "http://example.com/images/productivity.png"
69
- }
70
- Photo::STORE["d09ae4c6-0fc3-4c42-8fe8-6029530c3bed"] = {
71
- id: "d09ae4c6-0fc3-4c42-8fe8-6029530c3bed",
72
- title: "Ember Fox",
73
- src: "http://example.com/images/productivity-2.png"
74
- }
75
- end
76
-
77
- include_examples "api"
78
- end
79
- end
80
- end
81
- end
@@ -1,37 +0,0 @@
1
- module JSONAPI
2
- module Realizer
3
- class Action
4
- class Update < Action
5
- attr_accessor :resource
6
-
7
- def initialize(payload:, headers:, scope: nil)
8
- raise Error::MissingContentTypeHeader unless headers.key?("Content-Type")
9
- raise Error::InvalidContentTypeHeader unless headers.fetch("Content-Type") == JSONAPI::MEDIA_TYPE
10
-
11
- super(payload: payload, headers: headers, scope: scope)
12
-
13
- @resource = resource_class.new(adapter.find_via_call(relation, id))
14
-
15
- raise Error::MissingRootProperty unless @payload.key?("data") || @payload.key?("errors") || @payload.key?("meta")
16
- raise Error::MissingTypeResourceProperty if @payload.key?("data") && data.kind_of?(Hash) && !data.key?("type")
17
- raise Error::MissingTypeResourceProperty if @payload.key?("data") && data.kind_of?(Array) && !data.all? {|resource| resource.key?("type")}
18
- end
19
-
20
- def call
21
- adapter.assign_attributes_via_call(resource.model, attributes)
22
- adapter.assign_relationships_via_call(resource.model, relationships)
23
- end
24
-
25
- def model
26
- resource.model
27
- end
28
-
29
- private def id
30
- return data.fetch("id", nil) if data
31
-
32
- payload.fetch("id", nil)
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,170 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe JSONAPI::Realizer::Action::Update do
4
- let(:action) { described_class.new(payload: payload, headers: headers) }
5
-
6
- describe "#call" do
7
- subject { action.tap(&:call) }
8
-
9
- context "with no top-level data and no content-type header no accept headers" do
10
- let(:payload) do
11
- {}
12
- end
13
- let(:headers) do
14
- {}
15
- end
16
-
17
- it "raises an exception" do
18
- expect {subject}.to raise_exception(JSONAPI::Realizer::Error::MissingContentTypeHeader)
19
- end
20
- end
21
-
22
- context "with no top-level data and good content-type header no accept headers" do
23
- let(:payload) do
24
- {}
25
- end
26
- let(:headers) do
27
- {
28
- "Content-Type" => "application/vnd.api+json",
29
- }
30
- end
31
-
32
- it "raises an exception" do
33
- expect {subject}.to raise_exception(JSONAPI::Realizer::Error::MissingAcceptHeader)
34
- end
35
- end
36
-
37
- context "with no top-level data and wrong content-type header" do
38
- let(:payload) do
39
- {}
40
- end
41
- let(:headers) do
42
- {
43
- "Content-Type" => "application/json"
44
- }
45
- end
46
-
47
- it "raises an exception" do
48
- expect {subject}.to raise_exception(JSONAPI::Realizer::Error::InvalidContentTypeHeader)
49
- end
50
- end
51
-
52
- context "with no top-level data and good content-type header and wrong accept header" do
53
- let(:payload) do
54
- {}
55
- end
56
- let(:headers) do
57
- {
58
- "Content-Type" => "application/vnd.api+json",
59
- "Accept" => "application/json"
60
- }
61
- end
62
-
63
- it "raises an exception" do
64
- expect {subject}.to raise_exception(JSONAPI::Realizer::Error::InvalidAcceptHeader)
65
- end
66
- end
67
-
68
- context "with wrong top-level data and good headers" do
69
- let(:payload) do
70
- {
71
- "data" => ""
72
- }
73
- end
74
- let(:headers) do
75
- {
76
- "Content-Type" => "application/vnd.api+json",
77
- "Accept" => "application/vnd.api+json"
78
- }
79
- end
80
-
81
- it "raises an exception" do
82
- expect {subject}.to raise_exception(JSONAPI::Realizer::Error::MalformedDataRootProperty)
83
- end
84
- end
85
-
86
- context "with a good payload and good headers" do
87
- let(:payload) do
88
- {
89
- "data" => {
90
- "id" => "550e8400-e29b-41d4-a716-446655440000",
91
- "type" => "photos",
92
- "attributes" => {
93
- "title" => "Ember Hamster 2",
94
- "alt-text" => "A hamster logo.",
95
- "src" => "http://example.com/images/productivity-2.png"
96
- },
97
- "relationships" => {
98
- "active-photographer" => {
99
- "data" => { "type" => "photographer-accounts", "id" => "4b8a0af6-953d-4729-8b9a-1fa4eb18f3c9" }
100
- }
101
- }
102
- }
103
- }
104
- end
105
- let(:headers) do
106
- {
107
- "Content-Type" => "application/vnd.api+json",
108
- "Accept" => "application/vnd.api+json"
109
- }
110
- end
111
-
112
- shared_examples "api" do
113
- it "is the right model" do
114
- subject
115
-
116
- expect(action.model).to be_a_kind_of(Photo)
117
- end
118
-
119
- it "assigns the title attribute" do
120
- subject
121
-
122
- expect(action.model).to have_attributes(title: "Ember Hamster 2")
123
- end
124
-
125
- it "assigns the alt_text attribute" do
126
- subject
127
-
128
- expect(action.model).to have_attributes(alt_text: "A hamster logo.")
129
- end
130
-
131
- it "assigns the src attribute" do
132
- subject
133
-
134
- expect(action.model).to have_attributes(src: "http://example.com/images/productivity-2.png")
135
- end
136
-
137
- it "assigns the active_photographer attribute" do
138
- subject
139
-
140
- expect(action.model).to have_attributes(active_photographer: a_kind_of(Account))
141
- end
142
- end
143
-
144
- context "in a memory store", memory: true do
145
- before do
146
- Account::STORE["4b8a0af6-953d-4729-8b9a-1fa4eb18f3c9"] = {
147
- id: "4b8a0af6-953d-4729-8b9a-1fa4eb18f3c9",
148
- name: "Kurtis Rainbolt-Greene"
149
- }
150
- Photo::STORE["550e8400-e29b-41d4-a716-446655440000"] = {
151
- id: "550e8400-e29b-41d4-a716-446655440000",
152
- title: "Ember Hamster",
153
- src: "http://example.com/images/productivity.png"
154
- }
155
- end
156
-
157
- include_examples "api"
158
-
159
- it "updates the record" do
160
- expect(subject.model).to have_attributes(
161
- id: "550e8400-e29b-41d4-a716-446655440000",
162
- title: "Ember Hamster 2",
163
- alt_text: "A hamster logo.",
164
- src: "http://example.com/images/productivity-2.png"
165
- )
166
- end
167
- end
168
- end
169
- end
170
- end
@@ -1,46 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe JSONAPI::Realizer::Action do
4
- let(:headers) do
5
- {
6
- "Accept" => JSONAPI::MEDIA_TYPE
7
- }
8
- end
9
- let(:action) do
10
- ExampleAction.new(payload: payload, headers: headers, type: :photos)
11
- end
12
-
13
- describe "#includes" do
14
- subject { action.includes }
15
-
16
- context "with a two good and one bad" do
17
- let(:payload) do
18
- {
19
- "data" => nil,
20
- "include" => "active_photographer,active_photographer.posts.comments,active_photographer.posts"
21
- }
22
- end
23
-
24
- it "contains only the two good" do
25
- expect(subject).to eq([["active_photographer"], ["active_photographer", "posts"]])
26
- end
27
- end
28
- end
29
-
30
- describe "#fields" do
31
- subject { action.fields }
32
-
33
- context "with a two good and one bad" do
34
- let(:payload) do
35
- {
36
- "data" => nil,
37
- "fields" => "title,active_photographer.posts.comments.body,active_photographer.name"
38
- }
39
- end
40
-
41
- it "contains only the two good" do
42
- expect(subject).to eq([["title"], ["active_photographer", "name"]])
43
- end
44
- end
45
- end
46
- end
@@ -1,31 +0,0 @@
1
- module JSONAPI
2
- module Realizer
3
- class Adapter
4
- MEMORY = Proc.new do
5
- find_many_via do |model_class|
6
- model_class.all
7
- end
8
-
9
- find_via do |model_class, id|
10
- model_class.fetch(id)
11
- end
12
-
13
- assign_attributes_via do |model, attributes|
14
- model.assign_attributes(attributes)
15
- end
16
-
17
- assign_relationships_via do |model, relationships|
18
- model.assign_attributes(relationships)
19
- end
20
-
21
- sparse_fields do |model_class, fields|
22
- model_class
23
- end
24
-
25
- include_via do |model_class, includes|
26
- model_class
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,9 +0,0 @@
1
- module JSONAPI
2
- module Realizer
3
- class Error
4
- class InvalidAcceptHeader < Error
5
-
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module JSONAPI
2
- module Realizer
3
- class Error
4
- class MalformedDataRootProperty < Error
5
-
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module JSONAPI
2
- module Realizer
3
- class Error
4
- class MissingAcceptHeader < Error
5
-
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module JSONAPI
2
- module Realizer
3
- class Error
4
- class MissingTypeResourceProperty < Error
5
-
6
- end
7
- end
8
- end
9
- end