sinja 1.2.4 → 1.2.5
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/.travis.yml +0 -3
- data/README.md +38 -2
- data/demo-app/Gemfile +1 -1
- data/demo-app/app.rb +4 -2
- data/demo-app/classes/author.rb +1 -1
- data/demo-app/classes/post.rb +1 -1
- data/lib/sinja.rb +10 -7
- data/lib/sinja/config.rb +1 -0
- data/lib/sinja/helpers/serializers.rb +6 -1
- data/lib/sinja/resource.rb +1 -1
- data/lib/sinja/resource_routes.rb +6 -4
- data/lib/sinja/version.rb +1 -1
- data/sinja.gemspec +5 -5
- metadata +24 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9054bed54d4dd7bf2e166d3708c3726ba9c92d89
|
4
|
+
data.tar.gz: 1ade5511cf29f452d7f3d4555e1a153ea895c9a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cf864d75cf3232f2ab1f2699ea61e02db3a7503a446b07a6d1fe38261625b911f316e8a8851b44f13b7539d39b96a537699964c516918dd9676af0c6cf98ff0
|
7
|
+
data.tar.gz: 980b31489e1efd32956b33691bf78eb6c8cd1097a76af04cec58ab03abb567f4dd0d59ee42592079de8aa224b70beb29a3e7b6f7ee7bfb56c6453d33b09c056f
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -13,7 +13,7 @@
|
|
13
13
|
[][7]
|
14
14
|
[](https://gitter.im/sinja-rb/Lobby)
|
15
15
|
|
16
|
-
Sinja is a [Sinatra][1] [extension][10] for quickly building [RESTful][11],
|
16
|
+
Sinja is a [Sinatra 2.0][1] [extension][10] for quickly building [RESTful][11],
|
17
17
|
[{json:api}][2]-compliant web services, leveraging the excellent
|
18
18
|
[JSONAPI::Serializers][3] gem for payload serialization. It enhances Sinatra's
|
19
19
|
DSL to enable resource-, relationship-, and role-centric API development, and
|
@@ -40,6 +40,7 @@ framework like [Rails][16]. It's lightweight, ORM-agnostic, and
|
|
40
40
|
- [Configuration](#configuration)
|
41
41
|
- [Sinatra](#sinatra)
|
42
42
|
- [Sinja](#sinja)
|
43
|
+
- [Resources](#resources)
|
43
44
|
- [Resource Locators](#resource-locators)
|
44
45
|
- [Action Helpers](#action-helpers)
|
45
46
|
- [`resource`](#resource)
|
@@ -63,6 +64,7 @@ framework like [Rails][16]. It's lightweight, ORM-agnostic, and
|
|
63
64
|
- [Transactions](#transactions)
|
64
65
|
- [Side-Unloading Related Resources](#side-unloading-related-resources)
|
65
66
|
- [Side-Loading Relationships](#side-loading-relationships)
|
67
|
+
- [Deferring Relationships](#deferring-relationships)
|
66
68
|
- [Avoiding Null Foreign Keys](#avoiding-null-foreign-keys)
|
67
69
|
- [Coalesced Find Requests](#coalesced-find-requests)
|
68
70
|
- [Patchless Clients](#patchless-clients)
|
@@ -156,6 +158,9 @@ Or install it yourself as:
|
|
156
158
|
$ gem install sinja
|
157
159
|
```
|
158
160
|
|
161
|
+
Sinja is not compatible with Sinatra 1.x due to its limitations with nested
|
162
|
+
regexp-style namespaces and routes.
|
163
|
+
|
159
164
|
## Ol' Blue Eyes is Back
|
160
165
|
|
161
166
|
The "power" so to speak of implementing this functionality as a Sinatra
|
@@ -341,6 +346,36 @@ FooError` and `c.serializer_opts[:meta] = { foo: 'bar' }`) until you call
|
|
341
346
|
`freeze_jsonapi` to freeze the configuration store. **You should always freeze
|
342
347
|
the store after Sinja is configured and all your resources are defined.**
|
343
348
|
|
349
|
+
### Resources
|
350
|
+
|
351
|
+
Resources declared with the `resource` keyword (and relationships declared with
|
352
|
+
the `has_many` and `has_one` keywords) are dasherized and pluralized to match
|
353
|
+
the "type" property of JSONAPI::Serializers. For example, `resource :foo_bar`
|
354
|
+
would instruct Sinja to draw the appropriate routes under `/foo-bars`. Your
|
355
|
+
serializer type(s) should always match your resource (and relationship) names;
|
356
|
+
see the relevant [documentation][33] for more information.
|
357
|
+
|
358
|
+
The primary key portion of the route is extracted using a regular expression,
|
359
|
+
`\d+` by default. To use a different pattern, pass the `:pkre` resource route
|
360
|
+
option:
|
361
|
+
|
362
|
+
```ruby
|
363
|
+
resource :foo_bar, pkre: /\d+-\d+/ do
|
364
|
+
helpers do
|
365
|
+
def find(id)
|
366
|
+
# Look up a FooBar with a composite primary key of two integers.
|
367
|
+
FooBar[id.split('-', 2).map!(&:to_i)]
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
# ..
|
372
|
+
end
|
373
|
+
```
|
374
|
+
|
375
|
+
This helps Sinja (and Sinatra) disambiguate between standard {json:api} routes
|
376
|
+
used to fetch resources (e.g. `GET /foos/1`) and similarly-structured custom
|
377
|
+
routes (e.g. `GET /foos/recent`).
|
378
|
+
|
344
379
|
### Resource Locators
|
345
380
|
|
346
381
|
Much of Sinja's advanced functionality (e.g. updating and destroying resources,
|
@@ -1537,7 +1572,7 @@ logic.
|
|
1537
1572
|
| Feature | JR | Sinja |
|
1538
1573
|
| :-------------- | :------------------------------- | :------------------------------------------------ |
|
1539
1574
|
| Serializer | Built-in | [JSONAPI::Serializers][3] |
|
1540
|
-
| Framework | Rails | Sinatra, but easy to mount within others
|
1575
|
+
| Framework | Rails | Sinatra 2.0, but easy to mount within others |
|
1541
1576
|
| Routing | ActionDispatch::Routing | Mustermann |
|
1542
1577
|
| Caching | ActiveSupport::Cache | BYO |
|
1543
1578
|
| ORM | ActiveRecord/ActiveModel | BYO |
|
@@ -1614,3 +1649,4 @@ License](http://opensource.org/licenses/MIT).
|
|
1614
1649
|
[30]: https://github.com/mwpastore/sinja-sequel
|
1615
1650
|
[31]: http://jsonapi.org/implementations/#server-libraries-ruby
|
1616
1651
|
[32]: http://emberjs.com
|
1652
|
+
[33]: https://github.com/fotinakis/jsonapi-serializers#more-customizations
|
data/demo-app/Gemfile
CHANGED
data/demo-app/app.rb
CHANGED
@@ -10,7 +10,9 @@ require_relative 'classes/comment'
|
|
10
10
|
require_relative 'classes/post'
|
11
11
|
require_relative 'classes/tag'
|
12
12
|
|
13
|
-
|
13
|
+
Sequel::Model.finalize_associations
|
14
|
+
Sequel::Model.freeze
|
15
|
+
|
14
16
|
DB.freeze
|
15
17
|
|
16
18
|
configure :development do
|
@@ -34,7 +36,7 @@ end
|
|
34
36
|
|
35
37
|
resource :authors, &AuthorController
|
36
38
|
resource :comments, &CommentController
|
37
|
-
resource :posts, &PostController
|
39
|
+
resource :posts, :pkre=>/[\w-]+/, &PostController
|
38
40
|
resource :tags, &TagController
|
39
41
|
|
40
42
|
freeze_jsonapi
|
data/demo-app/classes/author.rb
CHANGED
data/demo-app/classes/post.rb
CHANGED
data/lib/sinja.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
require 'set'
|
3
3
|
|
4
4
|
require 'active_support/inflector'
|
5
|
-
require 'mustermann'
|
6
5
|
require 'sinatra/base'
|
7
6
|
require 'sinatra/namespace'
|
8
7
|
|
@@ -22,7 +21,6 @@ module Sinja
|
|
22
21
|
.to_h.freeze
|
23
22
|
|
24
23
|
def self.registered(app)
|
25
|
-
app.register Mustermann if Sinatra::VERSION[/^\d+/].to_i < 2
|
26
24
|
app.register Sinatra::Namespace
|
27
25
|
|
28
26
|
app.disable :protection, :show_exceptions, :static
|
@@ -102,9 +100,9 @@ module Sinja
|
|
102
100
|
end
|
103
101
|
end
|
104
102
|
|
105
|
-
# Sinatra
|
106
|
-
#
|
107
|
-
#
|
103
|
+
# Sinatra re-initializes `params' at namespace boundaries, so we'll
|
104
|
+
# reference its object_id in the flag to make sure we only re-normalize
|
105
|
+
# the parameters when necessary.
|
108
106
|
env['sinja.normalized'] = params.object_id
|
109
107
|
end
|
110
108
|
end
|
@@ -313,7 +311,7 @@ module Sinja
|
|
313
311
|
end
|
314
312
|
end
|
315
313
|
|
316
|
-
def resource(resource_name, konst=nil, &block)
|
314
|
+
def resource(resource_name, konst=nil, **opts, &block)
|
317
315
|
abort "Must supply proc constant or block for `resource'" \
|
318
316
|
unless block = (konst if konst.instance_of?(Proc)) || block
|
319
317
|
|
@@ -328,6 +326,9 @@ module Sinja
|
|
328
326
|
# trigger default procs
|
329
327
|
config = _sinja.resource_config[resource_name]
|
330
328
|
|
329
|
+
# incorporate route options
|
330
|
+
config[:route_opts].merge!(opts)
|
331
|
+
|
331
332
|
namespace %r{/#{resource_name}(?![^/])} do
|
332
333
|
define_singleton_method(:_resource_config) { config }
|
333
334
|
define_singleton_method(:resource_config) { config[:resource] }
|
@@ -338,12 +339,14 @@ module Sinja
|
|
338
339
|
end
|
339
340
|
end
|
340
341
|
|
341
|
-
before %r{/(
|
342
|
+
before %r{/(#{config[:route_opts][:pkre]})(?:/.*)?} do |id|
|
342
343
|
self.resource =
|
343
344
|
if env.key?('sinja.resource')
|
344
345
|
env['sinja.resource']
|
345
346
|
elsif respond_to?(:find)
|
346
347
|
find(id)
|
348
|
+
else
|
349
|
+
raise SinjaError, 'Resource locator not defined!'
|
347
350
|
end
|
348
351
|
|
349
352
|
raise NotFoundError, "Resource '#{id}' not found" unless resource
|
data/lib/sinja/config.rb
CHANGED
@@ -83,6 +83,7 @@ module Sinja
|
|
83
83
|
}}.curry
|
84
84
|
|
85
85
|
@resource_config = Hash.new { |h, k| h[k] = {
|
86
|
+
:route_opts=>{ :pkre=>/\d+/ },
|
86
87
|
:resource=>Hash.new(&action_proc[:resource]),
|
87
88
|
:has_many=>Hash.new { |rh, rk| rh[rk] = Hash.new(&action_proc[:has_many]) },
|
88
89
|
:has_one=>Hash.new { |rh, rk| rh[rk] = Hash.new(&action_proc[:has_one]) }
|
@@ -36,7 +36,12 @@ module Sinja
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def serialize_response_body
|
39
|
-
|
39
|
+
case response.content_type[/^[^;]+/]
|
40
|
+
when *[mime_type(:api_json), mime_type(:json), mime_type(:javascript)].freeze
|
41
|
+
JSON.send(settings._sinja.json_generator, response.body)
|
42
|
+
else
|
43
|
+
Array(response.body).map!(&:to_s)
|
44
|
+
end
|
40
45
|
rescue JSON::GeneratorError
|
41
46
|
raise BadRequestError, 'Unserializable entities in the response body'
|
42
47
|
end
|
data/lib/sinja/resource.rb
CHANGED
@@ -89,7 +89,7 @@ module Sinja
|
|
89
89
|
|
90
90
|
config = _resource_config[rel_type][rel] # trigger default proc
|
91
91
|
|
92
|
-
namespace %r{
|
92
|
+
namespace %r{/#{_resource_config[:route_opts][:pkre]}(?<r>/relationships)?/#{rel}(?![^/])} do
|
93
93
|
define_singleton_method(:resource_config) { config }
|
94
94
|
|
95
95
|
helpers Helpers::Nested do
|
@@ -82,17 +82,19 @@ module Sinja
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
app.
|
85
|
+
pkre = app._resource_config[:route_opts][:pkre]
|
86
|
+
|
87
|
+
app.options %r{/#{pkre}} do
|
86
88
|
allow :get=>:show, :patch=>:update, :delete=>:destroy
|
87
89
|
end
|
88
90
|
|
89
|
-
app.get
|
91
|
+
app.get %r{/(#{pkre})}, :qparams=>%i[include fields], :actions=>:show do |id|
|
90
92
|
tmp, opts = show(*[].tap { |a| a << id unless respond_to?(:find) })
|
91
93
|
raise NotFoundError, "Resource '#{id}' not found" unless tmp
|
92
94
|
serialize_model(tmp, opts)
|
93
95
|
end
|
94
96
|
|
95
|
-
app.patch
|
97
|
+
app.patch %r{/(#{pkre})}, :qparams=>%i[include fields], :actions=>:update do |id|
|
96
98
|
sanity_check!(id)
|
97
99
|
tmp, opts = transaction do
|
98
100
|
update(attributes).tap do
|
@@ -103,7 +105,7 @@ module Sinja
|
|
103
105
|
serialize_model?(tmp, opts)
|
104
106
|
end
|
105
107
|
|
106
|
-
app.delete
|
108
|
+
app.delete %r{/#{pkre}}, :actions=>:destroy do
|
107
109
|
_, opts = destroy
|
108
110
|
serialize_model?(nil, opts)
|
109
111
|
end
|
data/lib/sinja/version.rb
CHANGED
data/sinja.gemspec
CHANGED
@@ -37,18 +37,18 @@ Gem::Specification.new do |spec|
|
|
37
37
|
|
38
38
|
spec.required_ruby_version = '>= 2.3.0'
|
39
39
|
|
40
|
-
spec.add_dependency 'activesupport',
|
40
|
+
spec.add_dependency 'activesupport', '>= 4.2.8', '< 6'
|
41
41
|
spec.add_dependency 'json', '>= 1.8.3', '< 3'
|
42
|
-
spec.add_dependency 'jsonapi-serializers', '
|
43
|
-
spec.add_dependency '
|
44
|
-
spec.add_dependency 'sinatra',
|
45
|
-
spec.add_dependency 'sinatra-contrib', ">= #{ENV.fetch('sinatra', '1.4.7')}", '< 3'
|
42
|
+
spec.add_dependency 'jsonapi-serializers', '>= 0.16.2', '< 2'
|
43
|
+
spec.add_dependency 'sinatra', '>= 2.0.0.rc1', '< 3'
|
44
|
+
spec.add_dependency 'sinatra-contrib', '>= 2.0.0.rc1', '< 3'
|
46
45
|
|
47
46
|
spec.add_development_dependency 'bundler', '~> 1.11'
|
48
47
|
spec.add_development_dependency 'jdbc-sqlite3', '~> 3.8' if defined?(JRUBY_VERSION)
|
49
48
|
spec.add_development_dependency 'minitest', '~> 5.9'
|
50
49
|
spec.add_development_dependency 'minitest-hooks', '~> 1.4'
|
51
50
|
#spec.add_development_dependency 'munson', '~> 0.4' # in Gemfile
|
51
|
+
spec.add_development_dependency 'rack-test', '~> 0.6'
|
52
52
|
spec.add_development_dependency 'rake', '~> 12.0'
|
53
53
|
spec.add_development_dependency 'sequel', '~> 4.41'
|
54
54
|
#spec.add_development_dependency 'sinja-sequel', '~> 0.1' # in Gemfile
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinja
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Pastore
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,7 +16,7 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 4.2.
|
19
|
+
version: 4.2.8
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '6'
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 4.2.
|
29
|
+
version: 4.2.8
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '6'
|
@@ -52,25 +52,11 @@ dependencies:
|
|
52
52
|
version: '3'
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: jsonapi-serializers
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
56
|
-
requirements:
|
57
|
-
- - "~>"
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: '0.16'
|
60
|
-
type: :runtime
|
61
|
-
prerelease: false
|
62
|
-
version_requirements: !ruby/object:Gem::Requirement
|
63
|
-
requirements:
|
64
|
-
- - "~>"
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: '0.16'
|
67
|
-
- !ruby/object:Gem::Dependency
|
68
|
-
name: mustermann
|
69
55
|
requirement: !ruby/object:Gem::Requirement
|
70
56
|
requirements:
|
71
57
|
- - ">="
|
72
58
|
- !ruby/object:Gem::Version
|
73
|
-
version:
|
59
|
+
version: 0.16.2
|
74
60
|
- - "<"
|
75
61
|
- !ruby/object:Gem::Version
|
76
62
|
version: '2'
|
@@ -80,7 +66,7 @@ dependencies:
|
|
80
66
|
requirements:
|
81
67
|
- - ">="
|
82
68
|
- !ruby/object:Gem::Version
|
83
|
-
version:
|
69
|
+
version: 0.16.2
|
84
70
|
- - "<"
|
85
71
|
- !ruby/object:Gem::Version
|
86
72
|
version: '2'
|
@@ -90,7 +76,7 @@ dependencies:
|
|
90
76
|
requirements:
|
91
77
|
- - ">="
|
92
78
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
79
|
+
version: 2.0.0.rc1
|
94
80
|
- - "<"
|
95
81
|
- !ruby/object:Gem::Version
|
96
82
|
version: '3'
|
@@ -100,7 +86,7 @@ dependencies:
|
|
100
86
|
requirements:
|
101
87
|
- - ">="
|
102
88
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
89
|
+
version: 2.0.0.rc1
|
104
90
|
- - "<"
|
105
91
|
- !ruby/object:Gem::Version
|
106
92
|
version: '3'
|
@@ -110,7 +96,7 @@ dependencies:
|
|
110
96
|
requirements:
|
111
97
|
- - ">="
|
112
98
|
- !ruby/object:Gem::Version
|
113
|
-
version:
|
99
|
+
version: 2.0.0.rc1
|
114
100
|
- - "<"
|
115
101
|
- !ruby/object:Gem::Version
|
116
102
|
version: '3'
|
@@ -120,7 +106,7 @@ dependencies:
|
|
120
106
|
requirements:
|
121
107
|
- - ">="
|
122
108
|
- !ruby/object:Gem::Version
|
123
|
-
version:
|
109
|
+
version: 2.0.0.rc1
|
124
110
|
- - "<"
|
125
111
|
- !ruby/object:Gem::Version
|
126
112
|
version: '3'
|
@@ -166,6 +152,20 @@ dependencies:
|
|
166
152
|
- - "~>"
|
167
153
|
- !ruby/object:Gem::Version
|
168
154
|
version: '1.4'
|
155
|
+
- !ruby/object:Gem::Dependency
|
156
|
+
name: rack-test
|
157
|
+
requirement: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - "~>"
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0.6'
|
162
|
+
type: :development
|
163
|
+
prerelease: false
|
164
|
+
version_requirements: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - "~>"
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0.6'
|
169
169
|
- !ruby/object:Gem::Dependency
|
170
170
|
name: rake
|
171
171
|
requirement: !ruby/object:Gem::Requirement
|