sinja 1.2.4 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![{json:api} version](https://img.shields.io/badge/%7Bjson%3Aapi%7D%20version-1.0-lightgrey.svg)][7]
|
14
14
|
[![Chat in #sinja-rb on Gitter](https://badges.gitter.im/sinja-rb/Lobby.svg)](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
|