jsonapionify 0.11.9 → 0.11.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +158 -49
- data/lib/jsonapionify/api/resource/defaults/options.rb +3 -3
- data/lib/jsonapionify/api/resource/includer.rb +1 -1
- data/lib/jsonapionify/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
Nzg2ZGJhNjcxNmEzOTJmYWI4MjlkODQ5YjhhZWZkYWY5MjlkMTUyNQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YzE3OWY1MTA0ODhiZGZiNmZkMjcwYTZkMGRiZjFmY2ZlNjE0NmVhNQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ODE4MDFiZDFmOTlmNzBiOGU3ZDVlOTQ0YTE3NmMzYmU0Y2ZiM2EwNGIxMzcz
|
10
|
+
OTNlYWZlNDEzNmI5ZjBkNTdiNTBmNzNiYWIwZGUxNGMzZmJmNzE2NzQ1ZDc4
|
11
|
+
MzkyYTE3MWM4MDU5ODdkYmMwYjQ2ZWEyNTY5Yzc5ODU1MjgxZGY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZmU0NjY3YzU0ZDUyZjA0ZDY1NWM2N2NhZjQyZWY4NmJlODQ3OTI1ZjBiYTJl
|
14
|
+
NjAwMjM3OTgyZDU0OGQwMDM4YzZjNjYyODEzMWU2MDA5N2YwMjYxZjMwNjUx
|
15
|
+
MDk5YWViNTIxZTBjZTE0NDdkZmM4NWMxMTEzYTJkNzY3MjQ4NjM=
|
data/README.md
CHANGED
@@ -29,91 +29,200 @@ And then execute:
|
|
29
29
|
|
30
30
|
## Usage
|
31
31
|
|
32
|
-
###
|
32
|
+
### APIs
|
33
33
|
|
34
|
-
|
34
|
+
Api Definitions are the basis of JSONApi's DSL. They encompass resources that are available and can be run as standalone rack apps or be mounted within a rails app.
|
35
|
+
|
36
|
+
```
|
37
|
+
class MyCompanyApi < JSONAPIonify::Base
|
38
|
+
|
39
|
+
# Write a description for your API.
|
40
|
+
description <<~markdown
|
41
|
+
A description of your API, that will be available at the top of the documentation.
|
42
|
+
markdown
|
43
|
+
|
44
|
+
# Add some rack middleware
|
45
|
+
use Rack::SSL::Enforcer
|
46
|
+
|
47
|
+
# Handle Authorization
|
48
|
+
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
### Resources
|
53
|
+
|
54
|
+
Resources are what the API serves. They usually link to models. Resources are defined by calling `.define_resource` on the class of a defined api.
|
35
55
|
|
36
56
|
```ruby
|
37
|
-
|
38
|
-
|
57
|
+
MyCompanyApi.define_resource :users do
|
58
|
+
# ... The resource definition
|
39
59
|
end
|
40
60
|
```
|
41
61
|
|
42
|
-
|
62
|
+
#### Scope
|
63
|
+
Each api uses a scope to determine how to look up objects the serve the request. By default the resource will look for a class that is similar to it's scope.
|
43
64
|
|
44
65
|
```ruby
|
45
|
-
|
46
|
-
|
66
|
+
MyCompanyApi.define_resource :users do
|
67
|
+
scope { Person }
|
47
68
|
end
|
48
69
|
```
|
49
70
|
|
50
|
-
|
71
|
+
#### ID Attribute
|
72
|
+
JSONAPI needs an attribute to represent the object's id. This defaults to the `id` method, but can be overridden.
|
51
73
|
|
52
|
-
|
74
|
+
```ruby
|
75
|
+
MyCompanyApi.define_resource :users do
|
76
|
+
id :key
|
77
|
+
end
|
78
|
+
```
|
53
79
|
|
54
|
-
|
80
|
+
#### Instance Lookup
|
81
|
+
In order to locate an instance in the defined scope, the resource needs a instructions to do so. If the scope is a descendant of `ActiveRecord::Base`, it will automatically use `scope.find(id)` for the lookup.
|
55
82
|
|
83
|
+
```ruby
|
84
|
+
MyCompanyApi.define_resource :users do
|
85
|
+
instance { |scope, id| scope.find_by key: id }
|
86
|
+
end
|
56
87
|
```
|
57
|
-
class MyCompanyApi < JSONAPIonify::Base
|
58
88
|
|
59
|
-
|
60
|
-
|
61
|
-
A description of your API, that will be available at the top of the documentation.
|
62
|
-
markdown
|
63
|
-
|
64
|
-
# Add some rack middleware
|
65
|
-
use Rack::SSL::Enforcer
|
66
|
-
|
67
|
-
# Handle Authorization
|
89
|
+
#### Instance Builder
|
90
|
+
When creating an instance, the resource needs to know how to build a new object. If the scope is a descendant of `ActiveRecord::Base`, it will automatically use `scope.new` to build the object.
|
68
91
|
|
92
|
+
#### Contexts
|
93
|
+
Contexts are memoized blocks of code that are used throughout the request lifecycle of a resource. They can be referenced in [`hooks`](#hooks), [`actions`](#hooks), [`attributes`](#attributes), other [`contexts`](#contexts), etc. A context is defined as follows:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
MyCompanyApi.define_resource :users do
|
97
|
+
context :request_method do |context|
|
98
|
+
context.request.request_method
|
99
|
+
end
|
69
100
|
end
|
70
101
|
```
|
71
102
|
|
72
|
-
|
103
|
+
> **NOTE:** The gem ships with [predefined contexts](#predefined-contexts).
|
104
|
+
|
105
|
+
#### Attributes
|
106
|
+
Attributes define what fields will appear in the response. Attribute definitions require a name, a type, and a description. In addition, the attribute may include a block that defines how the value is resolved.
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
MyCompanyApi.define_resource :users do
|
110
|
+
attribute :name, types.String, 'the users name' do |attr_name, instance, context| do
|
111
|
+
instance.public_send(attr_name)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
##### Attribute types
|
117
|
+
Attributes require a type that map to JSON types. They are as follows:
|
118
|
+
`types.String`, `types.Boolean`, `types.Integer`, `types.Float`, `types.Array(of: ?)`, `types.Object`
|
119
|
+
|
120
|
+
> Array types take an `of` keyword of another type.
|
73
121
|
|
74
|
-
####
|
75
|
-
|
122
|
+
#### Relationships
|
123
|
+
Relationships define the way resources reference each other. There are two types of relationships. Relationships behave just like the resource they represent except it's scoped to the parent object. By default the scope of of a relationship resolves to a method equal to the name of the relationship. This can be overridden by passing a `Proc` to the resolve keyword. In addition, the default resource the object resolves to can be specified with the `resource` keyword. If a relationship is given a block it is treated the same as a resource definition, but it's [actions](#actions) are limited by the type of the relationship.
|
76
124
|
|
77
|
-
|
78
|
-
|
125
|
+
##### One-to-One
|
126
|
+
One-to-One relationships allow a parent resource to reference a single instance of another resource. It is defined as follows:
|
79
127
|
|
80
|
-
|
81
|
-
|
128
|
+
```ruby
|
129
|
+
MyCompanyApi.define_resource :users do
|
130
|
+
relates_to_one :thing, resolve: proc { |rel, instance, context| instance.public_send(rel) } do
|
131
|
+
replace
|
132
|
+
end
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
##### One-to-Many
|
137
|
+
One-to-One relationships allow a parent resource to reference a collection of another resource. It is defined as follows:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
MyCompanyApi.define_resource :users do
|
141
|
+
relates_to_many :friends, resource: :users, resolve: proc { |rel, instance, context| instance.public_send(rel) } do
|
142
|
+
add
|
143
|
+
replace
|
144
|
+
remove
|
145
|
+
end
|
146
|
+
end
|
147
|
+
```
|
82
148
|
|
83
|
-
####
|
84
|
-
|
149
|
+
#### Actions
|
150
|
+
Actions define the routes of a resource and what processing happens when that route is called.
|
85
151
|
|
86
|
-
|
87
|
-
The parsed attributes from the request object. Accessing this context, will also validate the data/structure.
|
152
|
+
**Root level resources have the following actions:**
|
88
153
|
|
89
|
-
|
90
|
-
|
154
|
+
| Action | Path
|
155
|
+
|--------|-----
|
156
|
+
| List | `GET /{resource}`
|
157
|
+
| Create | `POST /{resource}`
|
158
|
+
| Read | `GET /{resource}/{id}`
|
159
|
+
| Update | `PATCH /{resource}/{id}`
|
160
|
+
| Delete | `DELETE /{resource}/{id}`
|
91
161
|
|
92
|
-
|
93
|
-
The instance of the object found from the request's data/type and data/id attibutes. This is determined from the resource's defined scope.
|
162
|
+
**One-to-Many relationships resources have the following actions:**
|
94
163
|
|
95
|
-
|
96
|
-
|
164
|
+
| Action | Path
|
165
|
+
|--------|-----
|
166
|
+
| List | `GET /{resource}/{id}/{relationship}`
|
167
|
+
| Create | `POST /{resource}/{id}/{relationship}`
|
168
|
+
| Show | `GET /{resource}/{id}/relationships/{relationship}`
|
169
|
+
| Add | `POST /{resource}/{id}/relationships/{relationship}`
|
170
|
+
| Remove | `DELETE /{resource}/{id}/relationships/{relationship}`
|
171
|
+
| Replace| `PATCH /{resource}/{id}/relationships/{relationship}`
|
97
172
|
|
98
|
-
|
99
|
-
The data attribute in the top level object of the request
|
173
|
+
**One-to-One relationships resources have the following actions:**
|
100
174
|
|
101
|
-
|
102
|
-
|
175
|
+
| Action | Path
|
176
|
+
|--------|-----
|
177
|
+
| Read | `GET /{resource}/{id}/{relationship}`
|
178
|
+
| Show | `GET /{resource}/{id}/relationships/{relationship}`
|
179
|
+
| Replace| `PATCH /{resource}/{id}/relationships/{relationship}`
|
103
180
|
|
104
|
-
####
|
105
|
-
|
181
|
+
#### Hooks
|
182
|
+
Hooks can be invoked throughout the request lifecycle. They are defined in the following order:
|
106
183
|
|
107
|
-
|
108
|
-
|
184
|
+
```
|
185
|
+
before_request
|
186
|
+
before_{action}
|
187
|
+
before_commit_{action}
|
188
|
+
[commit action]
|
189
|
+
after_commit_{action}
|
190
|
+
before_response
|
191
|
+
[response]
|
192
|
+
after_response
|
193
|
+
after_{action}
|
194
|
+
after_request
|
195
|
+
```
|
109
196
|
|
110
|
-
|
111
|
-
The jsonapi object that will be used for the response.
|
197
|
+
A hook can be defined on a resource with:
|
112
198
|
|
113
|
-
|
114
|
-
|
199
|
+
```ruby
|
200
|
+
MyCompanyApi.define_resource :users do
|
201
|
+
before :create do |context|
|
202
|
+
puts context.request.request_method
|
203
|
+
end
|
204
|
+
end
|
205
|
+
```
|
115
206
|
|
207
|
+
### Predefined Contexts
|
116
208
|
|
209
|
+
| Context | Description
|
210
|
+
|--------- |----------
|
211
|
+
| `request` | The request.
|
212
|
+
| `request_body` | The raw body of the request.
|
213
|
+
| `request_object` | The JSON parsed into a JSONApionify Structure Object. Keys can be accessed as symbols.
|
214
|
+
| `id` | The id present in the request path, if present.
|
215
|
+
| `request_id` | The id of the requested resource, within the data attribute of the request object.
|
216
|
+
| `request_attributes` | The parsed attributes from the request object. Accessing this context, will also validate the data/structure.
|
217
|
+
| `request_relationships` | The parsed relationships from the request object. Accessing this context, will also validate the data/structure.
|
218
|
+
| `request_instance` | The instance of the object found from the request's data/type and data/id attributes. This is determined from the resource's defined scope.
|
219
|
+
| `request_resource` | The resource's scope determined from the request's data/type attribute.
|
220
|
+
| `request_data` | The data attribute in the top level object of the request
|
221
|
+
| `authentication` | An object containing the authentication data.
|
222
|
+
| `links` | The links object that will be present in the response.
|
223
|
+
| `meta` | The meta object that will be present in the response.
|
224
|
+
| `response_object` | The jsonapi object that will be used for the response.
|
225
|
+
| `response_collection` | The response for the collection.
|
117
226
|
|
118
227
|
## Development
|
119
228
|
|
@@ -5,7 +5,7 @@ module JSONAPIonify::Api
|
|
5
5
|
id :id
|
6
6
|
scope { self.type.classify.constantize }
|
7
7
|
collection do |scope, context|
|
8
|
-
if defined?(ActiveRecord) && scope < ActiveRecord::Base
|
8
|
+
if defined?(ActiveRecord) && scope.is_a?(Class) && scope < ActiveRecord::Base
|
9
9
|
scope.all
|
10
10
|
else
|
11
11
|
scope
|
@@ -13,7 +13,7 @@ module JSONAPIonify::Api
|
|
13
13
|
end
|
14
14
|
|
15
15
|
instance do |scope, key|
|
16
|
-
if defined?(ActiveRecord) && scope < ActiveRecord::Base
|
16
|
+
if defined?(ActiveRecord) && scope.is_a?(Class) && scope < ActiveRecord::Base
|
17
17
|
scope.find_by! id_attribute => key
|
18
18
|
else
|
19
19
|
raise NotImplementedError, 'instance not implemented'
|
@@ -21,7 +21,7 @@ module JSONAPIonify::Api
|
|
21
21
|
end
|
22
22
|
|
23
23
|
new_instance do |scope|
|
24
|
-
if defined?(ActiveRecord) && scope < ActiveRecord::Base
|
24
|
+
if defined?(ActiveRecord) && scope.is_a?(Class) && scope < ActiveRecord::Base
|
25
25
|
scope.new
|
26
26
|
else
|
27
27
|
raise NotImplementedError, 'scope not implemented'
|
@@ -7,7 +7,7 @@ module JSONAPIonify::Api
|
|
7
7
|
included do
|
8
8
|
before :list, :create, :read, :update do |context|
|
9
9
|
supports_includes = context.root_request? && context.includes.present?
|
10
|
-
is_active_record = defined?(ActiveRecord) && context.scope.
|
10
|
+
is_active_record = defined?(ActiveRecord) && context.scope.is_a?(Class) && context.scope < ActiveRecord::Base
|
11
11
|
if supports_includes && is_active_record
|
12
12
|
valid_includes = context.includes.select do |k, v|
|
13
13
|
context.scope._reflect_on_association(k)
|
data/lib/jsonapionify/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapionify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.
|
4
|
+
version: 0.11.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Waldrip
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|