restpack-resource 0.0.5 → 0.0.6
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.
- data/Gemfile.lock +1 -1
- data/README.md +149 -13
- data/Rakefile +10 -0
- data/lib/restpack-resource/resource/pageable.rb +7 -3
- data/lib/restpack-resource/resource.rb +1 -1
- data/lib/restpack-resource/version.rb +1 -1
- data/spec/resource/pageable_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +7 -1
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,25 +1,161 @@
|
|
1
1
|
# restpack-resource [](https://travis-ci.org/RestPack/restpack-resource) [](https://codeclimate.com/github/RESTpack/restpack-resource) [](https://gemnasium.com/RestPack/restpack-resource)
|
2
2
|
|
3
|
-
RESTful resource paging, side-loading, filtering and sorting
|
3
|
+
RESTful resource paging, side-loading, filtering and sorting.
|
4
|
+
|
5
|
+
Define your models:
|
4
6
|
|
5
7
|
```ruby
|
6
|
-
class
|
8
|
+
class Channel
|
7
9
|
include DataMapper::Resource
|
8
10
|
include RestPack::Resource
|
9
|
-
|
10
11
|
property :id, Serial
|
11
|
-
property :name, String, :length =>
|
12
|
-
property :created_by, Integer, :required => true
|
13
|
-
property :channel_id, Integer, :required => true
|
12
|
+
property :name, String, :length => 512
|
14
13
|
timestamps :at
|
15
|
-
|
16
|
-
validates_presence_of :name, :channel_id
|
17
14
|
|
18
|
-
|
19
|
-
|
15
|
+
validates_presence_of :name
|
16
|
+
|
17
|
+
has n, :applications
|
18
|
+
has n, :domains
|
19
|
+
has n, :configurations
|
20
20
|
|
21
|
-
resource_can_include :
|
22
|
-
resource_can_filter_by :
|
23
|
-
resource_can_sort_by :id
|
21
|
+
resource_can_include :applications, :domains, :configurations
|
22
|
+
resource_can_filter_by :id
|
23
|
+
resource_can_sort_by :id, :created_at, :modified_at
|
24
|
+
|
25
|
+
def as_resource
|
26
|
+
{
|
27
|
+
:id => id,
|
28
|
+
:name => name,
|
29
|
+
:url => "/api/v1/channels/#{id}.json"
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
Then you can do this in your API (Grape in this example):
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
module ChannelAPI
|
39
|
+
class V1 < Grape::API
|
40
|
+
version 'v1', :using => :path, :format => :json
|
41
|
+
|
42
|
+
resource :channels do
|
43
|
+
get do
|
44
|
+
Channel.paged_resource(params)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
24
48
|
end
|
25
49
|
```
|
50
|
+
|
51
|
+
Which gives you endpoints such as:
|
52
|
+
|
53
|
+
`/api/v1/channels.json?includes=applications,domains,configurations`
|
54
|
+
|
55
|
+
```javascript
|
56
|
+
{
|
57
|
+
"page": 1,
|
58
|
+
"page_count": 1,
|
59
|
+
"count": 2,
|
60
|
+
"previous_page": null,
|
61
|
+
"next_page": null,
|
62
|
+
"channels": [
|
63
|
+
{
|
64
|
+
"id": 1,
|
65
|
+
"name": "Developer Jobs Websites",
|
66
|
+
"url": "/api/v1/channels/1.json"
|
67
|
+
},
|
68
|
+
{
|
69
|
+
"id": 2,
|
70
|
+
"name": "Coffee Roulette",
|
71
|
+
"url": "/api/v1/channels/2.json"
|
72
|
+
}
|
73
|
+
],
|
74
|
+
"application_count": 3,
|
75
|
+
"applications": [
|
76
|
+
{
|
77
|
+
"id": 3,
|
78
|
+
"name": "Coffee Roulette Application",
|
79
|
+
"channel_id": 2,
|
80
|
+
"url": "/api/v1/applications/3.json"
|
81
|
+
},
|
82
|
+
{
|
83
|
+
"id": 2,
|
84
|
+
"name": "Python Jobs",
|
85
|
+
"channel_id": 1,
|
86
|
+
"url": "/api/v1/applications/2.json"
|
87
|
+
},
|
88
|
+
{
|
89
|
+
"id": 1,
|
90
|
+
"name": "Ruby Jobs",
|
91
|
+
"channel_id": 1,
|
92
|
+
"url": "/api/v1/applications/1.json"
|
93
|
+
}
|
94
|
+
],
|
95
|
+
"domain_count": 5,
|
96
|
+
"domains": [
|
97
|
+
{
|
98
|
+
"id": 5,
|
99
|
+
"identifier": "www.coffeeroulette.ie",
|
100
|
+
"channel_id": 2,
|
101
|
+
"application_id": 3,
|
102
|
+
"url": "/api/v1/domain/5.json"
|
103
|
+
},
|
104
|
+
{
|
105
|
+
"id": 4,
|
106
|
+
"identifier": "account.pythonjobs.ie",
|
107
|
+
"channel_id": 1,
|
108
|
+
"application_id": 2,
|
109
|
+
"url": "/api/v1/domain/4.json"
|
110
|
+
},
|
111
|
+
{
|
112
|
+
"id": 3,
|
113
|
+
"identifier": "www.pythonjobs.ie",
|
114
|
+
"channel_id": 1,
|
115
|
+
"application_id": 2,
|
116
|
+
"url": "/api/v1/domain/3.json"
|
117
|
+
},
|
118
|
+
{
|
119
|
+
"id": 2,
|
120
|
+
"identifier": "account.rubyjobs.ie",
|
121
|
+
"channel_id": 1,
|
122
|
+
"application_id": 1,
|
123
|
+
"url": "/api/v1/domain/2.json"
|
124
|
+
},
|
125
|
+
{
|
126
|
+
"id": 1,
|
127
|
+
"identifier": "www.rubyjobs.ie",
|
128
|
+
"channel_id": 1,
|
129
|
+
"application_id": 1,
|
130
|
+
"url": "/api/v1/domain/1.json"
|
131
|
+
}
|
132
|
+
],
|
133
|
+
"configuration_count": 2,
|
134
|
+
"configurations": [
|
135
|
+
{
|
136
|
+
"id": 11,
|
137
|
+
"name": "channel_key",
|
138
|
+
"value": {
|
139
|
+
"aaa": "111",
|
140
|
+
"bbb": "222"
|
141
|
+
},
|
142
|
+
"channel_id": 2,
|
143
|
+
"application_id": null,
|
144
|
+
"domain_id": null,
|
145
|
+
"url": "/api/v1/configuration/11.json"
|
146
|
+
},
|
147
|
+
{
|
148
|
+
"id": 10,
|
149
|
+
"name": "Key",
|
150
|
+
"value": {
|
151
|
+
"description": "Channel Config"
|
152
|
+
},
|
153
|
+
"channel_id": 2,
|
154
|
+
"application_id": null,
|
155
|
+
"domain_id": null,
|
156
|
+
"url": "/api/v1/configuration/10.json"
|
157
|
+
}
|
158
|
+
]
|
159
|
+
}
|
160
|
+
```
|
161
|
+
|
data/Rakefile
CHANGED
@@ -11,4 +11,14 @@ begin
|
|
11
11
|
t.rspec_opts = ['-cfs']
|
12
12
|
end
|
13
13
|
rescue LoadError
|
14
|
+
end
|
15
|
+
|
16
|
+
namespace :gem do
|
17
|
+
task :build do
|
18
|
+
sh "gem build restpack-resource.gemspec"
|
19
|
+
end
|
20
|
+
|
21
|
+
task :push do
|
22
|
+
sh "gem push restpack-resource-#{RestPack::Resource::VERSION}.gem"
|
23
|
+
end
|
14
24
|
end
|
@@ -21,7 +21,7 @@ module RestPack
|
|
21
21
|
:next_page => page.pager.next_page
|
22
22
|
}
|
23
23
|
|
24
|
-
paged_resource[self.resource_collection_name] = page.map { |item| item
|
24
|
+
paged_resource[self.resource_collection_name] = page.map { |item| model_as_resource(item) }
|
25
25
|
|
26
26
|
unless page.empty?
|
27
27
|
options[:includes].each do |association|
|
@@ -50,7 +50,7 @@ module RestPack
|
|
50
50
|
if relationship.is_a? DataMapper::Associations::ManyToOne::Relationship
|
51
51
|
side_loaded_entities += page.map do |entity| #TODO: GJ: PERF: we can bypass datamapper associations and get by a list of ids instead
|
52
52
|
relation = entity.send(relationship.name.to_sym)
|
53
|
-
relation ? relation
|
53
|
+
relation ? model_as_resource(relation) : nil
|
54
54
|
end
|
55
55
|
elsif relationship.is_a? DataMapper::Associations::OneToMany::Relationship
|
56
56
|
parent_key_name = relationship.parent_key.first.name
|
@@ -59,7 +59,7 @@ module RestPack
|
|
59
59
|
|
60
60
|
#TODO: GJ: configurable side-load page size
|
61
61
|
children = relationship.child_model.all(child_key_name.to_sym => foreign_keys).page({ per_page: 100 })
|
62
|
-
side_loaded_entities += children.map { |c| c
|
62
|
+
side_loaded_entities += children.map { |c| model_as_resource(c) }
|
63
63
|
|
64
64
|
count_key = "#{relationship.child_model_name.downcase}_count".to_sym
|
65
65
|
paged_resource[count_key] = children.pager.total
|
@@ -106,6 +106,10 @@ module RestPack
|
|
106
106
|
extracted.delete_if { |k, v| v.nil? }
|
107
107
|
end
|
108
108
|
|
109
|
+
def model_as_resource(model)
|
110
|
+
model.as_resource()
|
111
|
+
end
|
112
|
+
|
109
113
|
private
|
110
114
|
|
111
115
|
def resource_normalise_options!(options)
|
@@ -39,7 +39,7 @@ describe RestPack::Resource do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
context "when side-loading" do
|
42
|
-
it "should return related entities with their #
|
42
|
+
it "should return related entities with their #as_resource representation" do
|
43
43
|
result = Song.paged_resource(:includes => 'users')
|
44
44
|
result[:users][0][:custom].should == 'This is custom data'
|
45
45
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restpack-resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -100,12 +100,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
100
|
- - ! '>='
|
101
101
|
- !ruby/object:Gem::Version
|
102
102
|
version: '0'
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
hash: 808146894371819691
|
103
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
107
|
none: false
|
105
108
|
requirements:
|
106
109
|
- - ! '>='
|
107
110
|
- !ruby/object:Gem::Version
|
108
111
|
version: '0'
|
112
|
+
segments:
|
113
|
+
- 0
|
114
|
+
hash: 808146894371819691
|
109
115
|
requirements: []
|
110
116
|
rubyforge_project:
|
111
117
|
rubygems_version: 1.8.25
|