roda-contrib 0.2.0 → 0.3.0
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/CHANGELOG +3 -0
- data/README.md +2 -1
- data/doc/release_notes/0_3_0.rdoc +6 -0
- data/lib/roda/contrib/plugins/json_api.rb +177 -0
- data/lib/roda/contrib/version.rb +1 -1
- data/lib/roda/plugins/contrib_json_api.rb +3 -0
- data/roda-contrib.gemspec +2 -0
- metadata +32 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98460898008a6d9fa6213b1d5b77f524a9eac86c
|
4
|
+
data.tar.gz: d58b7165a2d2ba77371768f928ac5acfea445f26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c879c14dc8f0856ab6b088fd61bae9bd57e51a8704e052f1c8123e1f580b8d934462e3542cfd4ad2641fccff8c187d49701d0040264761312c07e366fb501da
|
7
|
+
data.tar.gz: ec7b4e96e1e8fecf2ad83e4916033083d71d61f98c28fb71ee46ce194169e000efdbbcef898c38d0caf819f4ff79bb157b3bf275ef83ae71fe268de94cc84c93
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -21,11 +21,12 @@ Or install it yourself as:
|
|
21
21
|
|
22
22
|
## Usage
|
23
23
|
|
24
|
-
Currently, the roda-contrib gem ships
|
24
|
+
Currently, the roda-contrib gem ships 4 plugins:
|
25
25
|
|
26
26
|
* load\_all
|
27
27
|
* multi\_dispatch
|
28
28
|
* csrf
|
29
|
+
* json\_api
|
29
30
|
|
30
31
|
When loading plugins from this gem, you should append the 'contrib' to the
|
31
32
|
symbol to load it. For example, if you want to use the multi\_dispatch plugin:
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'rack/parser'
|
2
|
+
require 'jsonapi/serializable'
|
3
|
+
require 'jsonapi/deserializable'
|
4
|
+
|
5
|
+
module RodaContrib
|
6
|
+
module Plugins
|
7
|
+
# This plugin intergrate Roda with the jsonapi-rb gem. It offers a simple
|
8
|
+
# interface to users, but a bit opinioned.
|
9
|
+
#
|
10
|
+
# === Prerequest
|
11
|
+
# To use this plugin, you should install the +rack-parser+ and the
|
12
|
+
# +jsonapi-rb+ gem first.
|
13
|
+
#
|
14
|
+
# === Configuration
|
15
|
+
# The +contrib_json_api+ plugin will not complain if you offer nothing to
|
16
|
+
# configure the boring middleware.
|
17
|
+
#
|
18
|
+
# App.plugin :contrib_json_api
|
19
|
+
#
|
20
|
+
# You can use options pass to this plugin to configure the +Rack::Parser+.
|
21
|
+
#
|
22
|
+
# App.plugin :contrib_json_api, {
|
23
|
+
# :parser => { 'application/json' => proc { |data| MultiJSON.parse(data) } },
|
24
|
+
# :handler => { 'application/json' => proc { |e, t| [400, {'Content-Type' => t}, ["broke"]] }
|
25
|
+
# }
|
26
|
+
#
|
27
|
+
# Check the rack-parser documentation for more information
|
28
|
+
#
|
29
|
+
# Optionally, if you already have the rack-parser middleware and don't want
|
30
|
+
# to setup the middleware again, you can use +:skip_middleware+ option to
|
31
|
+
# do so:
|
32
|
+
#
|
33
|
+
# App.plugin :contrib_json_api, skip_middleware: true
|
34
|
+
#
|
35
|
+
# === Usage
|
36
|
+
# The +contrib_json_api+ plugin only expose three methods to use.
|
37
|
+
#
|
38
|
+
# the +represent+ method is used for rendering the resources
|
39
|
+
# represent rc, with: SerializableRc
|
40
|
+
#
|
41
|
+
# the +represent_err+ method is used for rendering the errors, if you don't
|
42
|
+
# offer a title, 'model field validation error' will be used as title. the
|
43
|
+
# status is default to 400.
|
44
|
+
#
|
45
|
+
# represent rc.errors, title: 'gateway not reachable', status: 500
|
46
|
+
#
|
47
|
+
# the +json_params+ method is used to get the parsed data from the request
|
48
|
+
# body.
|
49
|
+
#
|
50
|
+
# a lot of options could be applied to customize the +represent+ and
|
51
|
+
# +represent_err+ method. Checkout the official jsonapi-rb documentation:
|
52
|
+
# https://jsonapi-rb.org/guides
|
53
|
+
#
|
54
|
+
# === Exmaple
|
55
|
+
# class App < Roda
|
56
|
+
# plugin :contrib_json_api
|
57
|
+
#
|
58
|
+
# route do |r|
|
59
|
+
# r.on 'product' do
|
60
|
+
# r.is :id do |id|
|
61
|
+
# @rc = Product.with_pk(id.to_i)
|
62
|
+
#
|
63
|
+
# r.get do
|
64
|
+
# represent @rc, with: SerializableProduct
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# r.post do
|
68
|
+
# @rc.set_fields(json_params)
|
69
|
+
# if @rc.valid?
|
70
|
+
# @rc.save_changes
|
71
|
+
# represent @rc, with: SerializableProduct
|
72
|
+
# else
|
73
|
+
# represent_err @rc.errors
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
module JsonApi
|
81
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
82
|
+
|
83
|
+
JSONAPI_MEDIA_TYPE = 'application/vnd.api+json'.freeze
|
84
|
+
|
85
|
+
RACK_PASER_PARAMS = 'rack.parser.result'.freeze
|
86
|
+
|
87
|
+
DEFAULT_JSON_PARSER = proc { |data| JSON.parse(data) }
|
88
|
+
|
89
|
+
DEFAULT_ERROR_HANDLER = proc { |err, type|
|
90
|
+
e = [SerializableError.new(title: 'invalid JSON doc', err: err, status: 400)]
|
91
|
+
msg = JSONAPI::Serializable::ErrorRenderer.render(e, {})
|
92
|
+
[400, { CONTENT_TYPE => JSONAPI_MEDIA_TYPE }, [msg]]
|
93
|
+
}
|
94
|
+
|
95
|
+
DEFAULT_RACK_PARSER_OPTS = {
|
96
|
+
parsers: { JSONAPI_MEDIA_TYPE => DEFAULT_JSON_PARSER },
|
97
|
+
handlers: { JSONAPI_MEDIA_TYPE => DEFAULT_ERROR_HANDLER }
|
98
|
+
}.freeze
|
99
|
+
|
100
|
+
class SerializableError < JSONAPI::Serializable::Error
|
101
|
+
title { @title }
|
102
|
+
status { @status }
|
103
|
+
detail { @err.is_a?(Exception) ? @err.message : @err }
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.configure(app, opts={})
|
107
|
+
return if opts[:skip_middleware]
|
108
|
+
|
109
|
+
app.instance_exec do
|
110
|
+
@middleware.each do |(mid, *rest), _|
|
111
|
+
if mid.equal?(::Rack::Parser)
|
112
|
+
rest[0].merge!(opts)
|
113
|
+
build_rack_app
|
114
|
+
return
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
if opts.empty?
|
119
|
+
use ::Rack::Parser, DEFAULT_RACK_PARSER_OPTS.dup
|
120
|
+
return
|
121
|
+
elsif opts[:parsers].nil? || opts[:pasers][JSONAPI_MEDIA_TYPE].nil?
|
122
|
+
opts[:parsers] = { JSONAPI_MEDIA_TYPE => DEFAULT_JSON_PARSER }
|
123
|
+
use ::Rack::Parser, opts
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
module InstanceMethods
|
129
|
+
def represent(rc, options={})
|
130
|
+
options[:class] = options.delete(:with) unless options[:class]
|
131
|
+
rendered = JSONAPI::Serializable::Renderer.render(rc, options)
|
132
|
+
|
133
|
+
response[CONTENT_TYPE] = JSONAPI_MEDIA_TYPE
|
134
|
+
response.write(rendered)
|
135
|
+
request.halt
|
136
|
+
end
|
137
|
+
|
138
|
+
def represent_err(errs, options={})
|
139
|
+
t = options.delete(:title) || 'model field validation failed'
|
140
|
+
s = options.delete[:status] || 400
|
141
|
+
e = if errs.resond_to? :full_messages
|
142
|
+
errs.full_messages.map { |err| SerializableError.new(title: t, err: err, status: s) }
|
143
|
+
else
|
144
|
+
[SerializableError.new(title: t, err: errs, status: s)]
|
145
|
+
end
|
146
|
+
rendered = JSONAPI::Serializable::ErrorRenderer.render(e, options)
|
147
|
+
|
148
|
+
response.status = s
|
149
|
+
response[CONTENT_TYPE] = JSONAPI_MEDIA_TYPE
|
150
|
+
response.write(rendered)
|
151
|
+
request.halt
|
152
|
+
end
|
153
|
+
|
154
|
+
def json_params
|
155
|
+
parse_jsonapi env[RACK_PASER_PARAMS]
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
def parse_jsonapi(rc, options={})
|
160
|
+
klass = options[:with] || JSONAPI::Deserializable::Resource
|
161
|
+
begin
|
162
|
+
result = klass.call(rc)
|
163
|
+
rescue JSONAPI::Parser::InvalidDocument => e
|
164
|
+
errs = [SerializableError.new(title: 'Invalid JSONAPI doc', error: e, status: 400)]
|
165
|
+
rendered = JSONAPI::Serializable::ErrorRenderer.render(errs, {})
|
166
|
+
|
167
|
+
response.status = 400
|
168
|
+
response[CONTENT_TYPE] = JSONAPI_MEDIA_TYPE
|
169
|
+
response.write(rendered)
|
170
|
+
request.halt
|
171
|
+
end
|
172
|
+
result
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
data/lib/roda/contrib/version.rb
CHANGED
data/roda-contrib.gemspec
CHANGED
@@ -29,6 +29,8 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_development_dependency 'yard'
|
30
30
|
spec.add_development_dependency 'rack-test'
|
31
31
|
spec.add_development_dependency 'rack_csrf'
|
32
|
+
spec.add_development_dependency 'rack-parser'
|
33
|
+
spec.add_development_dependency 'jsonapi-rb'
|
32
34
|
|
33
35
|
spec.add_dependency 'roda', '~> 2.0'
|
34
36
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roda-contrib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- luciusgone
|
@@ -94,6 +94,34 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rack-parser
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: jsonapi-rb
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: roda
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,14 +154,17 @@ files:
|
|
126
154
|
- Rakefile
|
127
155
|
- doc/release_notes/0_1_0.rdoc
|
128
156
|
- doc/release_notes/0_2_0.rdoc
|
157
|
+
- doc/release_notes/0_3_0.rdoc
|
129
158
|
- lib/roda/contrib.rb
|
130
159
|
- lib/roda/contrib/action.rb
|
131
160
|
- lib/roda/contrib/action/dispatchable.rb
|
132
161
|
- lib/roda/contrib/plugins/csrf.rb
|
162
|
+
- lib/roda/contrib/plugins/json_api.rb
|
133
163
|
- lib/roda/contrib/plugins/load_all.rb
|
134
164
|
- lib/roda/contrib/plugins/multi_dispatch.rb
|
135
165
|
- lib/roda/contrib/version.rb
|
136
166
|
- lib/roda/plugins/contrib_csrf.rb
|
167
|
+
- lib/roda/plugins/contrib_json_api.rb
|
137
168
|
- lib/roda/plugins/contrib_load_all.rb
|
138
169
|
- lib/roda/plugins/contrib_multi_dispatch.rb
|
139
170
|
- roda-contrib.gemspec
|