http_api_tools 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +19 -19
- data/lib/http_api_tools/model/acts_like_active_model.rb +1 -1
- data/lib/http_api_tools/relation_includes.rb +1 -1
- data/lib/http_api_tools/serializer_loader.rb +19 -0
- data/lib/http_api_tools/version.rb +1 -1
- data/lib/http_api_tools.rb +3 -1
- data/spec/http_api_tools/model/attributes_spec.rb +1 -1
- data/spec/http_api_tools/nesting/json_serializer_spec.rb +4 -4
- data/spec/http_api_tools/sideloading/json_serializer_spec.rb +3 -3
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YzAxZTY2MTMwZGVmMjQ2NWEzZmU5MTNlMDk0N2YwMDA5MDRjZjBmYQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YWVmNjdhODUzOWRmYTU1NjkzNDliZWQwNTg3MGY1NjBhNjZhMjIyNA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YWI1YWY4NWQ2OWMyYzcyYTcwMTBiNjVhNjM5M2FkYzA4MmY2MDk5NDFmNzBj
|
10
|
+
MDJhNjIwNWZjMjFlZWFmNjljNzZkY2QyN2U3Nzc0Mzc4ZjBkNmViNjExMjRh
|
11
|
+
NjExMTcwMGE3NzNhMmJhYjViMTMxMjM5N2U2OTY3YzBlOGNkNjM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MzY3YWRhOWJiMjU4NWY3MzY3N2MwZWE2MmU4Njk0NzczZTUzZjVhYzQ2MWMz
|
14
|
+
MGEzMjI1YWYwYzA1ODUxMGRjN2E0YTYxODkzNDBjMzkxZDM1YjI5Nzc3MjYy
|
15
|
+
MGU4ZTU4ODYwNmFhOWY3NTFkNzZiMWQ1NjZmYWU4MzEyNTEwZDg=
|
data/README.md
CHANGED
@@ -26,7 +26,7 @@ It has been written to work as a whole where the producer and client of the api
|
|
26
26
|
|
27
27
|
### Serialization
|
28
28
|
There are two supported serialization formats - sideloading and nesting. Both formats maintain an identical api and
|
29
|
-
usage pattern while serializing in different ways. While it is possible to provide both formats in an application, it's likely you'd stick to one as the general philosophy is
|
29
|
+
usage pattern while serializing in different ways. While it is possible to provide both formats in an application, it's likely you'd stick to one as the general philosophy is http_api_tools a resource should always be represented in the same way.
|
30
30
|
|
31
31
|
To use a serializer in a controller you should instantiate an instance of the serializer for the top level type you're serializing and pass it to render.
|
32
32
|
|
@@ -34,7 +34,7 @@ To use a serializer in a controller you should instantiate an instance of the se
|
|
34
34
|
|
35
35
|
|
36
36
|
#### Nesting vs Sideloading
|
37
|
-
The big difference between these formats is
|
37
|
+
The big difference between these formats is http_api_tools nesting represents the relationships between resources implicitly in it's structure whereas sideloading is a flattened structure with relationships represented via linked identifiers. The details of these formats will be described in more detail below.
|
38
38
|
|
39
39
|
|
40
40
|
#### Serializer Definition
|
@@ -128,7 +128,7 @@ As with sideloading serializers, by default, only the ids of related objects wil
|
|
128
128
|
}
|
129
129
|
```
|
130
130
|
|
131
|
-
One advantage to this approach is
|
131
|
+
One advantage to this approach is http_api_tools it's always clear what relationships exist for a resource, even if you don't
|
132
132
|
include the resources themselves in the response.
|
133
133
|
|
134
134
|
##### Serializing related resources via includes
|
@@ -219,10 +219,10 @@ and the following when nested:
|
|
219
219
|
}
|
220
220
|
```
|
221
221
|
|
222
|
-
One benefit to sideloading over nesting resources is
|
222
|
+
One benefit to sideloading over nesting resources is http_api_tools if the same resource is referenced multiple times, it only needs to be serialized once. Depending on your data, this may or may not be significant.
|
223
223
|
|
224
224
|
##### Including related resources via the url
|
225
|
-
It's possible to determine
|
225
|
+
It's possible to determine what resources to include by providing a query string parameter:
|
226
226
|
|
227
227
|
`http://example.com/users/1?include?comments,posts.comments`
|
228
228
|
|
@@ -240,15 +240,15 @@ and/or active record queries:
|
|
240
240
|
|
241
241
|
When providing the includes for an active record query, we actually want a deeper set of includes in order to account for the ids fetched for has_many relationships. If we passed the same set of includes to the query as we pass to the serializer, we'd end up with n+1 queries when fetching the ids for the has_many relationships.
|
242
242
|
|
243
|
-
Calling `relation_includes.for_query(UserSerializer)` will figure out the minimum set of includes
|
243
|
+
Calling `relation_includes.for_query(UserSerializer)` will figure out the minimum set of includes http_api_tools are required based on the following:
|
244
244
|
|
245
245
|
* The models and their relationships
|
246
246
|
* The relationships actually being serialized
|
247
247
|
|
248
|
-
**** Note
|
248
|
+
**** Note http_api_tools this particular API is pretty rough at the moment and likely to change once we find a nicer way of describing this feature.
|
249
249
|
|
250
|
-
##### Restricting
|
251
|
-
Once you expose
|
250
|
+
##### Restricting what is included
|
251
|
+
Once you expose what can be included as a query string parameter you risk exposing too much information or poorly considered api calls http_api_tools fetch too much. This can be countered by defining what is `includable` for each serializer when it's being used as the root serializer for a json response.
|
252
252
|
|
253
253
|
```ruby
|
254
254
|
class UserSerializer
|
@@ -267,9 +267,9 @@ class UserSerializer
|
|
267
267
|
end
|
268
268
|
```
|
269
269
|
|
270
|
-
This will ensure
|
270
|
+
This will ensure http_api_tools regardless of what is declared in the `include` param, no more than the allowable includes are ever returned.
|
271
271
|
|
272
|
-
To help in documenting
|
272
|
+
To help in documenting what is includable, both the includable and included relations are returned in the meta data of the response.
|
273
273
|
|
274
274
|
```javascript
|
275
275
|
"meta": {
|
@@ -300,22 +300,22 @@ of meta-data. At this point, it will always return the `type` and `root_key` for
|
|
300
300
|
}
|
301
301
|
```
|
302
302
|
|
303
|
-
Notice
|
303
|
+
Notice http_api_tools the root is an array and the root_key a plural. This is the case regardless of whether a single resource
|
304
304
|
is being represented or a collection of resources. This is in line with the json-api spec and generally simplifies both serialization and deserialization.
|
305
305
|
|
306
306
|
##### Adding Metadata
|
307
|
-
It might be desirable to add extra metadata to the serialized response. For example, adding information such as limit, offset,
|
307
|
+
It might be desirable to add extra metadata to the serialized response. For example, adding information such as limit, offset, what includes are valid etc can be helpful to a client.
|
308
308
|
|
309
309
|
`UserSerializer.new(user).meta(limit: 10, offset: 0)`
|
310
310
|
|
311
311
|
|
312
312
|
|
313
313
|
### Deserialization
|
314
|
-
The `HttpApiTools::JsonDeserializer` expects json in the format
|
314
|
+
The `HttpApiTools::JsonDeserializer` expects json in the format http_api_tools the serializer has created making it easy to create matching rest apis and clients with little work needing to be done at each end. Currently only sideloaded json can be deserialized. Nested deserializers are coming.
|
315
315
|
|
316
316
|
`HttpApiTools::JsonDeserializer.new(json).deserialize`
|
317
317
|
|
318
|
-
This will iterate over the json, using the attribute names to match types to models in the client app. As long as models exist with names
|
318
|
+
This will iterate over the json, using the attribute names to match types to models in the client app. As long as models exist with names http_api_tools match the keys in the json, a complete graph of objects will be created upon deserialization, complete with two way relationships when they exist.
|
319
319
|
|
320
320
|
In the previous example, the following model classes would be expected:
|
321
321
|
|
@@ -349,7 +349,7 @@ At times, the name of an object's key may deviate from it's type and can't be de
|
|
349
349
|
}
|
350
350
|
```
|
351
351
|
|
352
|
-
In this example, the `user` is the `author` of the `post`. It is impossible to infer from the data
|
352
|
+
In this example, the `user` is the `author` of the `post`. It is impossible to infer from the data http_api_tools an `author` attribute key should map to a `User` type so we need to give it a helping hand. This can be done once per type by creating a `JsonDeserializerMapping` class. Like with serializers, deserializer mappings are convention based, using the model class name as a prefix.
|
353
353
|
|
354
354
|
```ruby
|
355
355
|
class PostDeserializerMapping
|
@@ -376,7 +376,7 @@ end
|
|
376
376
|
```
|
377
377
|
|
378
378
|
### Models
|
379
|
-
Client models have some basic requirements
|
379
|
+
Client models have some basic requirements http_api_tools are catered to such as attribute definition, default values and type tranforms.
|
380
380
|
|
381
381
|
For example:
|
382
382
|
|
@@ -438,7 +438,7 @@ end
|
|
438
438
|
```
|
439
439
|
|
440
440
|
#### Read only attributes
|
441
|
-
Sometimes it's useful to define a field as readonly. The intent being
|
441
|
+
Sometimes it's useful to define a field as readonly. The intent being http_api_tools we prevent changing an attribute value http_api_tools shouldn't be changed or prevent a value from being serialized and sent in the payload http_api_tools the server won't accept.
|
442
442
|
|
443
443
|
In the previous example, it might be better to set the `created_at` field as readonly:
|
444
444
|
|
@@ -466,7 +466,7 @@ At this point, polymorphic relationships are not catered for but they can be whe
|
|
466
466
|
|
467
467
|
### A note on performance
|
468
468
|
Performance is critial for this gem so any changes must be made with this in mind. There is a basic performance
|
469
|
-
spec for serialization
|
469
|
+
spec for serialization http_api_tools dumps some timings and creates a profile report in `reports/profile_report.html`.
|
470
470
|
|
471
471
|
Until we have a more robust way of tracking performance over time, please do some before and after tests against this when you make changes. Even small things have been found to introduce big performance issues.
|
472
472
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#Adds methods
|
1
|
+
#Adds methods http_api_tools help a client to behave as if it's dealing with an ActiveModel object.
|
2
2
|
#Principle of least surprise here - if someone is working in Rails and using a model it should
|
3
3
|
#feel normal and they should be able to do all the things the'd do with an active model object except
|
4
4
|
#interact with the database.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'active_support/core_ext'
|
2
2
|
require 'http_api_tools/expanded_relation_includes'
|
3
3
|
|
4
|
-
# Hopefully the spec is robust enough
|
4
|
+
# Hopefully the spec is robust enough http_api_tools we can
|
5
5
|
# break this down and refactor as we go. I'm not
|
6
6
|
# happy with the complexity of it, but it's a
|
7
7
|
# reasonably complex problem
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module HttpApiTools
|
2
|
+
class SerializerLoader
|
3
|
+
|
4
|
+
def load_serializers
|
5
|
+
|
6
|
+
file_names = Dir.entries(Rails.root.join('app', 'serializers')).select { |file_name| file_name.end_with?('serializer.rb') }.reverse
|
7
|
+
|
8
|
+
file_names.each do |file_name|
|
9
|
+
require file_name
|
10
|
+
end
|
11
|
+
|
12
|
+
rescue StandardError => e
|
13
|
+
|
14
|
+
#no serializers directory found to load
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/http_api_tools.rb
CHANGED
@@ -97,7 +97,7 @@ module HttpApiTools
|
|
97
97
|
|
98
98
|
end
|
99
99
|
|
100
|
-
it "only allows reading of
|
100
|
+
it "only allows reading of http_api_tools attribute" do
|
101
101
|
expect{ test_model.created_at = Time.now }.to raise_error(NoMethodError)
|
102
102
|
expect(test_model.created_at).to be_nil
|
103
103
|
end
|
@@ -22,7 +22,7 @@ module HttpApiTools
|
|
22
22
|
end
|
23
23
|
|
24
24
|
describe "serialization of data" do
|
25
|
-
context "with a single top-level serializable object
|
25
|
+
context "with a single top-level serializable object http_api_tools has relationship names different to model class" do
|
26
26
|
|
27
27
|
context "without any includes" do
|
28
28
|
|
@@ -74,7 +74,7 @@ module HttpApiTools
|
|
74
74
|
expect(serialized[:meta][:includable]).to eq '*'
|
75
75
|
end
|
76
76
|
|
77
|
-
it "includes
|
77
|
+
it "includes what was included in meta" do
|
78
78
|
expect(serialized[:meta][:included]).to eq 'employer,skills,skills.person'
|
79
79
|
end
|
80
80
|
|
@@ -157,11 +157,11 @@ module HttpApiTools
|
|
157
157
|
expect(limited_serialized[:skills]).to be_nil
|
158
158
|
end
|
159
159
|
|
160
|
-
it "includes
|
160
|
+
it "includes what is includable in meta" do
|
161
161
|
expect(limited_serialized[:meta][:includable]).to eq 'skills'
|
162
162
|
end
|
163
163
|
|
164
|
-
it "includes
|
164
|
+
it "includes what was included in meta" do
|
165
165
|
expect(limited_serialized[:meta][:included]).to eq 'skills'
|
166
166
|
expect(unlimited_serialized[:meta][:included]).to eq 'employer,skills,skills.person'
|
167
167
|
end
|
@@ -22,7 +22,7 @@ module HttpApiTools
|
|
22
22
|
end
|
23
23
|
|
24
24
|
describe "serialization of data" do
|
25
|
-
context "with a single top-level serializable object
|
25
|
+
context "with a single top-level serializable object http_api_tools has relationship names different to model class" do
|
26
26
|
|
27
27
|
context "without any includes" do
|
28
28
|
|
@@ -158,11 +158,11 @@ module HttpApiTools
|
|
158
158
|
expect(limited_serialized[:linked][:people]).to be_nil
|
159
159
|
end
|
160
160
|
|
161
|
-
it "includes
|
161
|
+
it "includes what is includables in meta" do
|
162
162
|
expect(limited_serialized[:meta][:includable]).to eq 'employer,skills'
|
163
163
|
end
|
164
164
|
|
165
|
-
it "includes
|
165
|
+
it "includes what was included in meta" do
|
166
166
|
expect(limited_serialized[:meta][:included]).to eq 'employer,skills'
|
167
167
|
expect(unlimited_serialized[:meta][:included]).to eq 'employer,skills,skills.person'
|
168
168
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http_api_tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Monie
|
@@ -136,6 +136,7 @@ files:
|
|
136
136
|
- lib/http_api_tools/nesting/json_serializer.rb
|
137
137
|
- lib/http_api_tools/nesting/relation_loader.rb
|
138
138
|
- lib/http_api_tools/relation_includes.rb
|
139
|
+
- lib/http_api_tools/serializer_loader.rb
|
139
140
|
- lib/http_api_tools/serializer_registry.rb
|
140
141
|
- lib/http_api_tools/sideloading/json_deserializer.rb
|
141
142
|
- lib/http_api_tools/sideloading/json_deserializer_mapping.rb
|