api_resource 0.6.21 → 0.6.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/Gemfile.lock +1 -1
- data/LICENSE.txt +22 -0
- data/README.md +16 -9
- data/docs/Attributes.md +64 -0
- data/docs/Caching.md +45 -0
- data/docs/GettingStarted.md +149 -0
- data/docs/Relationships.md +136 -0
- data/docs/ResourceDefinition.md +80 -0
- data/docs/Retrieval.md +279 -0
- data/docs/Serialization.md +56 -0
- data/lib/api_resource/associations/has_many_remote_object_proxy.rb +2 -2
- data/lib/api_resource/attributes.rb +16 -4
- data/lib/api_resource/base.rb +98 -19
- data/lib/api_resource/conditions/abstract_condition.rb +241 -129
- data/lib/api_resource/conditions/include_condition.rb +7 -1
- data/lib/api_resource/conditions/pagination_condition.rb +37 -0
- data/lib/api_resource/conditions/where_condition.rb +19 -0
- data/lib/api_resource/conditions.rb +18 -2
- data/lib/api_resource/connection.rb +27 -13
- data/lib/api_resource/exceptions.rb +11 -11
- data/lib/api_resource/finders/abstract_finder.rb +176 -95
- data/lib/api_resource/finders/multi_object_association_finder.rb +10 -9
- data/lib/api_resource/finders/resource_finder.rb +59 -49
- data/lib/api_resource/finders/single_finder.rb +5 -6
- data/lib/api_resource/finders/single_object_association_finder.rb +52 -51
- data/lib/api_resource/finders.rb +1 -1
- data/lib/api_resource/formats/file_upload_format.rb +75 -0
- data/lib/api_resource/formats.rb +4 -1
- data/lib/api_resource/response.rb +108 -0
- data/lib/api_resource/scopes.rb +62 -5
- data/lib/api_resource/serializer.rb +1 -1
- data/lib/api_resource/typecasters/boolean_typecaster.rb +1 -0
- data/lib/api_resource/typecasters/integer_typecaster.rb +1 -0
- data/lib/api_resource/typecasters/time_typecaster.rb +12 -4
- data/lib/api_resource/version.rb +1 -1
- data/lib/api_resource.rb +1 -0
- data/spec/lib/associations/has_one_remote_object_proxy_spec.rb +4 -4
- data/spec/lib/associations_spec.rb +3 -3
- data/spec/lib/attributes_spec.rb +16 -1
- data/spec/lib/base_spec.rb +121 -39
- data/spec/lib/conditions/{abstract_conditions_spec.rb → abstract_condition_spec.rb} +23 -11
- data/spec/lib/conditions/pagination_condition_spec.rb +88 -0
- data/spec/lib/finders/multi_object_association_finder_spec.rb +55 -27
- data/spec/lib/finders/resource_finder_spec.rb +26 -2
- data/spec/lib/finders/single_object_association_finder_spec.rb +14 -6
- data/spec/lib/finders_spec.rb +81 -81
- data/spec/lib/observing_spec.rb +3 -4
- data/spec/lib/response_spec.rb +18 -0
- data/spec/lib/scopes_spec.rb +25 -1
- data/spec/lib/typecasters/boolean_typecaster_spec.rb +1 -1
- data/spec/lib/typecasters/integer_typecaster_spec.rb +1 -1
- data/spec/lib/typecasters/time_typecaster_spec.rb +6 -0
- data/spec/support/files/bg-awesome.jpg +0 -0
- data/spec/support/mocks/test_resource_mocks.rb +26 -16
- data/spec/support/requests/test_resource_requests.rb +27 -23
- metadata +24 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7509a2d4163d8d10f94db97575b59deec95663a2
|
4
|
+
data.tar.gz: a540de64f15a6196656ca31b43efdee89c816c66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1860666ecc1aa458a8f35121c6b98017af00161f1ce418476d12c823efa77b4f5e19b24ba6c559b9855cfccbe9ec1827d37d5c3f12400a1bedbf3aadf282a20
|
7
|
+
data.tar.gz: 9d22a6386bc3f13727f7a3e2ea56112b07012874237f340b78b77d5b07a7422c009f160ecb01a0311c6ffa341ea24f8fa63f1595b2137f815d8b8a9607ab7c0a
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown
|
data/Gemfile.lock
CHANGED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Ethan Langevin
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -2,23 +2,30 @@
|
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/LifebookerInc/api_resource.png)](https://travis-ci.org/LifebookerInc/api_resource)
|
4
4
|
|
5
|
-
|
5
|
+
ApiResource is an ActiveModel-compatible library for retrieving and
|
6
|
+
persisting data via APIs
|
6
7
|
|
7
|
-
|
8
|
+
## Getting Started
|
8
9
|
|
9
|
-
|
10
|
+
1. Add this line to your application's Gemfile:
|
10
11
|
|
11
|
-
|
12
|
+
gem 'api_resource'
|
12
13
|
|
13
|
-
|
14
|
+
1. And then execute:
|
14
15
|
|
15
|
-
|
16
|
+
$ bundle
|
16
17
|
|
17
|
-
|
18
|
+
1. Follow our {file:docs/GettingStarted.md Getting Started Guide} to learn more about how to use ApiResource
|
18
19
|
|
19
|
-
##
|
20
|
+
## Read more about some of the core concepts in ApiResource
|
21
|
+
|
22
|
+
### {file:docs/ResourceDefinition.md The Resource Definition}
|
23
|
+
### {file:docs/Attributes.md Attributes}
|
24
|
+
### {file:docs/Relationships.md Relationships}
|
25
|
+
### {file:docs/Retrieval.md Retrieving Records}
|
26
|
+
### {file:docs/Serialization.md Serialization}
|
27
|
+
### {file:docs/Caching.md Caching}
|
20
28
|
|
21
|
-
TODO: Write usage instructions here
|
22
29
|
|
23
30
|
## Contributing
|
24
31
|
|
data/docs/Attributes.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# Attributes
|
2
|
+
|
3
|
+
Attributes are read from the Server application's
|
4
|
+
{file:docs/ResourceDefinition.md Resource Definition}.
|
5
|
+
|
6
|
+
## Visibility
|
7
|
+
|
8
|
+
### Public
|
9
|
+
|
10
|
+
Can read and write, data is sent to the server if it has changed
|
11
|
+
|
12
|
+
### Protected
|
13
|
+
|
14
|
+
Can read only. Cannot set or mass-assign
|
15
|
+
|
16
|
+
# Resource definition
|
17
|
+
# {
|
18
|
+
# ...
|
19
|
+
# protected : [
|
20
|
+
# ['updated_at', 'time']
|
21
|
+
# ]
|
22
|
+
# ...
|
23
|
+
# }
|
24
|
+
|
25
|
+
Resource::Person.new(updated_at: Time.now) # => Raises error
|
26
|
+
resource = Resource::Person.new
|
27
|
+
resource.updated_at = Time.now #=> Raises error
|
28
|
+
|
29
|
+
### Private
|
30
|
+
|
31
|
+
Field is not even definted or included in the
|
32
|
+
{file:docs/ResourceDefinition.md Resource Definition}. For more
|
33
|
+
info see {http://path/to/server/docs ApiResourceServer ApiResource Server}
|
34
|
+
|
35
|
+
|
36
|
+
## Typecasting
|
37
|
+
|
38
|
+
ApiResource supports the following types:
|
39
|
+
|
40
|
+
1. Array
|
41
|
+
1. Boolean
|
42
|
+
1. Date
|
43
|
+
1. Float
|
44
|
+
1. Integer
|
45
|
+
1. String
|
46
|
+
1. Time
|
47
|
+
|
48
|
+
Attributes are given a type in the
|
49
|
+
{file:docs/ResourceDefinition.md Resource Definition}. For more
|
50
|
+
info see {http://path/to/server/docs ApiResourceServer ApiResource Server}
|
51
|
+
|
52
|
+
## Dirty Tracking
|
53
|
+
|
54
|
+
ApiResource::Base includes ActiveModel::Dirty and uses Dirty Tracking to
|
55
|
+
determine which attributes to send to the server on save. Only attributes
|
56
|
+
that have changed are sent to the server.
|
57
|
+
|
58
|
+
person = Resource::Person.find(1)
|
59
|
+
person.attributes
|
60
|
+
# => { first_name: 'Aaron', last_name: 'Burr', ...}
|
61
|
+
person.last_name = 'Copeland'
|
62
|
+
|
63
|
+
person.save
|
64
|
+
# PUT /people/1.json { person: { last_name: 'Copeland' } }
|
data/docs/Caching.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Caching
|
2
|
+
|
3
|
+
Caching is implemented at the connection level and caches the
|
4
|
+
respone body and headers of any GET request made while caching
|
5
|
+
is active for the period specified
|
6
|
+
|
7
|
+
## Where is it cached?
|
8
|
+
|
9
|
+
By default we use Rails.cache
|
10
|
+
|
11
|
+
# Configure the cache to use a MemoryStore
|
12
|
+
ApiResource::Base.cache = ActiveSupport::Cache::MemoryStore.new
|
13
|
+
|
14
|
+
|
15
|
+
## Activating caching globally
|
16
|
+
|
17
|
+
This will cache all GET requests for 30 seconds
|
18
|
+
|
19
|
+
ApiResource::Base.ttl = 30.seconds
|
20
|
+
|
21
|
+
## Activating caching for a given find call
|
22
|
+
|
23
|
+
Resource::Person.born_on(Date.today).expires_in(30.seconds).all
|
24
|
+
|
25
|
+
|
26
|
+
## Cache expiration
|
27
|
+
|
28
|
+
Resource::Person.born_on(Date.today).expires_in(30.seconds).all
|
29
|
+
|
30
|
+
# no HTTP request here
|
31
|
+
Resource::Person.born_on(Date.today).expires_in(30.seconds).all
|
32
|
+
|
33
|
+
sleep(30)
|
34
|
+
|
35
|
+
# cache has expired - new HTTP Request
|
36
|
+
Resource::Person.born_on(Date.today).expires_in(30.seconds).all
|
37
|
+
|
38
|
+
|
39
|
+
## Differing cache times for the same URL
|
40
|
+
|
41
|
+
Cache requests are specific to the cache interval specified. For example,
|
42
|
+
if a find with a 60 second TTL and then another with a 30 second TTL will
|
43
|
+
make two calls
|
44
|
+
|
45
|
+
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# Getting Started with ApiResource
|
2
|
+
|
3
|
+
## Creating a model in your Client application
|
4
|
+
|
5
|
+
All of your models will extend {ApiResource::Base}
|
6
|
+
|
7
|
+
# This must be loaded explicitly or created in a directory that is
|
8
|
+
# autoloaded
|
9
|
+
|
10
|
+
# lib/resources/person.rb
|
11
|
+
module Resources
|
12
|
+
class Person < ApiResource::Base
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
## Adding a resource definition in your Server application
|
17
|
+
|
18
|
+
On the server-side, you will need to activate the resource
|
19
|
+
|
20
|
+
# app/modeperson.rb
|
21
|
+
class Person < ActiveRecord::Base
|
22
|
+
|
23
|
+
# this gives Person access to the methods necessary
|
24
|
+
# to create a resrouce definition
|
25
|
+
include LifebookerCommon::Model::Resource
|
26
|
+
|
27
|
+
# Example attributes
|
28
|
+
#
|
29
|
+
# :first_name, :last_name, :birthday
|
30
|
+
|
31
|
+
# Example validation
|
32
|
+
#
|
33
|
+
validates :birthday,
|
34
|
+
presence: true
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
Read more about {file:docs/ResourceDefinition.md Resource Definitions}
|
39
|
+
|
40
|
+
## Adding basic routes and controller actions to your Server application
|
41
|
+
|
42
|
+
# config/routes.rb
|
43
|
+
resources :people
|
44
|
+
|
45
|
+
# app/controllers/people_controller.rb
|
46
|
+
class PeopleController < ApplicationController
|
47
|
+
|
48
|
+
respond_to :json
|
49
|
+
|
50
|
+
# GET /people/new
|
51
|
+
def new
|
52
|
+
respond_with(Person.resource_definition)
|
53
|
+
end
|
54
|
+
|
55
|
+
# GET /people
|
56
|
+
def index
|
57
|
+
respond_with(Person.all)
|
58
|
+
end
|
59
|
+
|
60
|
+
# GET /people/:id
|
61
|
+
def show
|
62
|
+
@person = Person.find(params[:id])
|
63
|
+
respond_with(@person)
|
64
|
+
end
|
65
|
+
|
66
|
+
# POST /people
|
67
|
+
def create
|
68
|
+
@person = Person.create(params[:person])
|
69
|
+
respond_with(@person)
|
70
|
+
end
|
71
|
+
|
72
|
+
# PUT /people/:id
|
73
|
+
def update
|
74
|
+
@person = Person.find(params[:id])
|
75
|
+
@person.update_attributes(params[:person])
|
76
|
+
respond_with(@person)
|
77
|
+
end
|
78
|
+
|
79
|
+
# DELETE /people/:id
|
80
|
+
def destory
|
81
|
+
@person = Person.find(params[:id])
|
82
|
+
@person.destory
|
83
|
+
respond_with(@person)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
## Creating a new record in your Client application
|
88
|
+
|
89
|
+
ApiResource knows about your Server model's attributes through its
|
90
|
+
{file:docs/ResourceDefinition.md Resource Definition}, so you can just
|
91
|
+
set its attributes and call {#save}
|
92
|
+
|
93
|
+
It attempts to replicate the behaviors of ActiveRecord as closely as possible
|
94
|
+
|
95
|
+
# in any part of your Client application
|
96
|
+
@person = Resources::Person.new(first_name: 'Aaron', last_name: 'Burr')
|
97
|
+
@person.save #=> true/false
|
98
|
+
|
99
|
+
# if we have errors
|
100
|
+
@person.errors #=> ActiveModel::Errors
|
101
|
+
@person.errors.full_messages #=> ['Birthday is required.']
|
102
|
+
|
103
|
+
Read more about {file:docs/Persistance.md Persistance}
|
104
|
+
|
105
|
+
## Finding a single record in your Client application
|
106
|
+
|
107
|
+
# raises ApiResource::ResourceNotFound if no Person is found on
|
108
|
+
# the server and a 404 is returned
|
109
|
+
#
|
110
|
+
# GET /people/#{params[:id]}.json
|
111
|
+
@person = Resource::Person.find(params[:id])
|
112
|
+
|
113
|
+
## Finding multiple records in your Client application
|
114
|
+
|
115
|
+
The query interface mimics ActiveRecord/Arel and reads scopes from the
|
116
|
+
{file:docs/ResourceDefinition.md Resource Definitions}
|
117
|
+
|
118
|
+
# GET /people.json
|
119
|
+
@people = Resource::Person.all # all people
|
120
|
+
|
121
|
+
# GET /people.json?first_name=Aaron
|
122
|
+
@people = Resource::Person.where(first_name: 'Aaron')
|
123
|
+
#=> ApiResource::ScopeCondition - Loaded on demand when you start
|
124
|
+
# iterating through the resource (e.g. @people.each {...})
|
125
|
+
|
126
|
+
For more information see {file:docs/Retrieval.md#scopes Scopes}
|
127
|
+
|
128
|
+
## Updating a record
|
129
|
+
|
130
|
+
To update, you just find one or more records and call
|
131
|
+
{ApiResource::Base#update_attributes #update_attributes} on each record
|
132
|
+
|
133
|
+
@person = Resource::Person.find(1)
|
134
|
+
@person.update_attributes(
|
135
|
+
first_name: 'Joseph',
|
136
|
+
last_name: 'Stalin',
|
137
|
+
birthday: nil
|
138
|
+
)
|
139
|
+
# => true/false
|
140
|
+
|
141
|
+
@person.errors.full_messages # => ['Birthday is required.']
|
142
|
+
|
143
|
+
## Deleting a record
|
144
|
+
|
145
|
+
To delete, just find a record and call {ApiResource::Base#destroy #destroy}
|
146
|
+
on it
|
147
|
+
|
148
|
+
@person = Resource::Person.find(1)
|
149
|
+
@person.destroy # => true/false
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# Relationships
|
2
|
+
|
3
|
+
ApiResource mimics ActiveRecord's relationships, but loads the data via an
|
4
|
+
API or instantiates a record when data is nested
|
5
|
+
|
6
|
+
## There are 3 ways to include associated data in a response for APIResource
|
7
|
+
|
8
|
+
The proper approach will depend on the specifics of the Server and Client
|
9
|
+
applications. For example, if an associated resource is used just about
|
10
|
+
every time the parent is retrieved, it makes sense to nest it.
|
11
|
+
|
12
|
+
In general, nesting increases the overall complexity of the Server app and
|
13
|
+
slows it down though, so it should be used with caution
|
14
|
+
|
15
|
+
Models in the Server application
|
16
|
+
|
17
|
+
class Person < ActiveRecord::Base
|
18
|
+
belongs_to :state
|
19
|
+
has_many :weapons, through: :person_weapons
|
20
|
+
end
|
21
|
+
|
22
|
+
class PersonWeapon < ActiveRecord::Base
|
23
|
+
belongs_to :weapon
|
24
|
+
belongs_to :person
|
25
|
+
end
|
26
|
+
|
27
|
+
class Weapon < ActiveRecord::Base
|
28
|
+
scope :sharp, -> { where(sharp: true) }
|
29
|
+
end
|
30
|
+
|
31
|
+
class State < ActiveRecord::Base
|
32
|
+
end
|
33
|
+
|
34
|
+
The Server application would need to have Controllers defined to expose these
|
35
|
+
models and their {file:docs/ResourceDefinition.md Resource Definitions}. For
|
36
|
+
an example of that visit {file:docs/GettingStarted.md Getting Started}
|
37
|
+
|
38
|
+
|
39
|
+
1. Include the data nested in the response
|
40
|
+
|
41
|
+
# GET /people/1.json
|
42
|
+
|
43
|
+
# Response
|
44
|
+
{
|
45
|
+
first_name: 'Aaron',
|
46
|
+
last_name: 'Burr',
|
47
|
+
weapons: [
|
48
|
+
{ id: 1, name: 'Ax', sharp: true },
|
49
|
+
{ id: 2, name: 'Pistol', sharp: false }
|
50
|
+
],
|
51
|
+
state: { id: 10, name: 'New York' }
|
52
|
+
}
|
53
|
+
|
54
|
+
# in the Client application
|
55
|
+
person = Resource::Person.find(1)
|
56
|
+
person.state.name # => 'New York'
|
57
|
+
person.weapons.length # => 2
|
58
|
+
|
59
|
+
# no additional HTTP calls are made
|
60
|
+
|
61
|
+
1. Include a link to the data in the response
|
62
|
+
|
63
|
+
# GET /people/1.json
|
64
|
+
|
65
|
+
# Response
|
66
|
+
{
|
67
|
+
first_name: 'Aaron',
|
68
|
+
last_name: 'Burr',
|
69
|
+
weapons: [ { service_uri: '/people/1/weapons' } ],
|
70
|
+
state: { service_uri: '/states/10' }
|
71
|
+
}
|
72
|
+
|
73
|
+
# in the Client application
|
74
|
+
person = Resource::Person.find(1)
|
75
|
+
person.state.name # => 'New York'
|
76
|
+
person.weapons.length # => 2
|
77
|
+
|
78
|
+
# 2 additional HTTP calls are made
|
79
|
+
# (1 to each :service_uri provided)
|
80
|
+
|
81
|
+
1. Include the ids for the associated objects in the response
|
82
|
+
|
83
|
+
# GET /people/1.json
|
84
|
+
|
85
|
+
# Response
|
86
|
+
{
|
87
|
+
first_name: 'Aaron',
|
88
|
+
last_name: 'Burr',
|
89
|
+
weapon_ids: [ 1, 2 ],
|
90
|
+
state_id: 10
|
91
|
+
}
|
92
|
+
|
93
|
+
# in the Client application
|
94
|
+
person = Resource::Person.find(1)
|
95
|
+
person.state.name # => 'New York'
|
96
|
+
person.weapons.length # => 2
|
97
|
+
|
98
|
+
# 2 additional HTTP calls are made
|
99
|
+
# GET /weapons.json?ids[]=1&ids[]=2
|
100
|
+
# and
|
101
|
+
# GET /states/10.json
|
102
|
+
|
103
|
+
|
104
|
+
## Applying a scope to a relationship
|
105
|
+
|
106
|
+
Any scope on the relationship model can be applied to the relationship and
|
107
|
+
will be passed on to the server
|
108
|
+
|
109
|
+
*Note:* This does not work with embedded data because it has already
|
110
|
+
be loaded with the parent resource
|
111
|
+
|
112
|
+
|
113
|
+
@person = Resource::Person.find(1)
|
114
|
+
|
115
|
+
# GET /people/1/weapons.json
|
116
|
+
@person.weapons
|
117
|
+
# => [ Resource::Weapon(id: 1, name: 'Ax', sharp: true), Resource::Weapon(id: 2, name: 'Pistol', sharp: false) ]
|
118
|
+
|
119
|
+
# GET /people/1/weapons.json?sharp=true
|
120
|
+
@person.weapons.sharp
|
121
|
+
# => [ Resource::Weapon(id: 1, name: 'Ax', sharp: true) ]
|
122
|
+
|
123
|
+
## Saving associated records
|
124
|
+
|
125
|
+
By default, ApiResource assumes that any modifications to individual records
|
126
|
+
in an Association will be saved directly via that record
|
127
|
+
|
128
|
+
ApiResource::Base does provide the option to `:include_associations` on save
|
129
|
+
to mass-update records. This includes the data with the parent record's save
|
130
|
+
call.
|
131
|
+
|
132
|
+
@person = Resource::Person.find(1)
|
133
|
+
|
134
|
+
@person.state.name = 'I renamed New York'
|
135
|
+
@person.save(include_associations: [:state])
|
136
|
+
# PUT /people.json { state: { name: 'I renamed New York', id: 10 } }
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# The Resource Definition
|
2
|
+
|
3
|
+
The Resource Definition is the way that the Server application communicates
|
4
|
+
the properties and scopes of its models to the Client application
|
5
|
+
|
6
|
+
## How do I set this up in my Server application?
|
7
|
+
|
8
|
+
Full documentation is available at {http://path/to/server/docs ApiResourceServer}
|
9
|
+
|
10
|
+
## Definition Components
|
11
|
+
|
12
|
+
### Attributes
|
13
|
+
|
14
|
+
Attributes are typically fields in the database, but can be declared using
|
15
|
+
`virtual_attribute` in the Server's model as well
|
16
|
+
|
17
|
+
#### Visibility
|
18
|
+
|
19
|
+
ApiResourceServer hooks into `attr_protected` and provides `attr_private` to
|
20
|
+
communicate visibility of different attributes
|
21
|
+
|
22
|
+
|
23
|
+
### Scopes
|
24
|
+
|
25
|
+
ApiResource also hooks into ActiveRecord's `scope` to communicate
|
26
|
+
the models in the Server applications' scopes
|
27
|
+
|
28
|
+
### Associations
|
29
|
+
|
30
|
+
ApiResource also hooks into ActiveRecord's `has_many`, `belongs_to` and
|
31
|
+
`has_one` associations to communicate the models in the Server applications'
|
32
|
+
associations
|
33
|
+
|
34
|
+
## Exposing the Resource Definition
|
35
|
+
|
36
|
+
The Server application is responsible for exposing the Resource Definition
|
37
|
+
to the Client application. It should do so at
|
38
|
+
`GET /PLURALIZED_RESOURCE_NAME/new.json`
|
39
|
+
|
40
|
+
|
41
|
+
## Examples
|
42
|
+
|
43
|
+
See {http://path/to/server/docs ApiResourceServer} for more information
|
44
|
+
on declaring your attributes
|
45
|
+
|
46
|
+
|
47
|
+
## Final Resource Definition
|
48
|
+
|
49
|
+
{
|
50
|
+
attributes: {
|
51
|
+
public: [
|
52
|
+
["birthday", Date],
|
53
|
+
["first_name", "string"],
|
54
|
+
["last_name", "string"]
|
55
|
+
],
|
56
|
+
protected: [
|
57
|
+
["created_at", "time"],
|
58
|
+
["id", "integer"]
|
59
|
+
["updated_at", "time"]
|
60
|
+
]
|
61
|
+
},
|
62
|
+
associations : {
|
63
|
+
belongs_to: {
|
64
|
+
state: {}
|
65
|
+
},
|
66
|
+
has_many: {
|
67
|
+
friends: {}
|
68
|
+
}
|
69
|
+
|
70
|
+
},
|
71
|
+
scopes: {
|
72
|
+
active: {},
|
73
|
+
born_on: { date: :req }
|
74
|
+
}
|
75
|
+
|
76
|
+
}
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
|