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.
- checksums.yaml +4 -4
- data/README.md +13 -104
- data/lib/jsonapi/realizer.rb +26 -25
- data/lib/jsonapi/realizer/action.rb +2 -2
- data/lib/jsonapi/realizer/adapter.rb +21 -58
- data/lib/jsonapi/realizer/adapter/active_record.rb +38 -17
- data/lib/jsonapi/realizer/adapter_spec.rb +3 -2
- data/lib/jsonapi/realizer/configuration.rb +22 -0
- data/lib/jsonapi/realizer/context.rb +8 -0
- data/lib/jsonapi/realizer/controller.rb +55 -0
- data/lib/jsonapi/realizer/error.rb +10 -9
- data/lib/jsonapi/realizer/error/invalid_content_type_header.rb +5 -0
- data/lib/jsonapi/realizer/error/invalid_data_type_property.rb +13 -0
- data/lib/jsonapi/realizer/error/invalid_root_property.rb +13 -0
- data/lib/jsonapi/realizer/error/{duplicate_registration.rb → missing_data_type_property.rb} +1 -1
- data/lib/jsonapi/realizer/error/resource_attribute_not_found.rb +14 -0
- data/lib/jsonapi/realizer/error/resource_relationship_not_found.rb +14 -0
- data/lib/jsonapi/realizer/resource.rb +278 -73
- data/lib/jsonapi/realizer/resource/attribute.rb +23 -0
- data/lib/jsonapi/realizer/resource/configuration.rb +27 -0
- data/lib/jsonapi/realizer/resource/relation.rb +31 -0
- data/lib/jsonapi/realizer/resource_spec.rb +55 -8
- data/lib/jsonapi/realizer/version.rb +1 -1
- data/lib/jsonapi/realizer_spec.rb +22 -119
- metadata +70 -20
- data/lib/jsonapi/realizer/action/create.rb +0 -36
- data/lib/jsonapi/realizer/action/create_spec.rb +0 -165
- data/lib/jsonapi/realizer/action/destroy.rb +0 -27
- data/lib/jsonapi/realizer/action/destroy_spec.rb +0 -81
- data/lib/jsonapi/realizer/action/index.rb +0 -29
- data/lib/jsonapi/realizer/action/index_spec.rb +0 -75
- data/lib/jsonapi/realizer/action/show.rb +0 -35
- data/lib/jsonapi/realizer/action/show_spec.rb +0 -81
- data/lib/jsonapi/realizer/action/update.rb +0 -37
- data/lib/jsonapi/realizer/action/update_spec.rb +0 -170
- data/lib/jsonapi/realizer/action_spec.rb +0 -46
- data/lib/jsonapi/realizer/adapter/memory.rb +0 -31
- data/lib/jsonapi/realizer/error/invalid_accept_header.rb +0 -9
- data/lib/jsonapi/realizer/error/malformed_data_root_property.rb +0 -9
- data/lib/jsonapi/realizer/error/missing_accept_header.rb +0 -9
- 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
|