rack-backend-api 0.0.3 → 0.0.4
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.
- data/README.md +47 -0
- data/lib/backend_api.rb +4 -4
- data/lib/sequel_rack_backend_api_adapter.rb +1 -0
- data/rack-backend-api.gemspec +1 -1
- data/test/spec_backend_api.rb +39 -2
- metadata +4 -4
data/README.md
CHANGED
@@ -164,6 +164,52 @@ nice interface using Ajax and getting the best of what the API has to offer.
|
|
164
164
|
The forms are really meant to be requested via an XHR,
|
165
165
|
so that you have access to style and javascript widgets like a date-picker for example.
|
166
166
|
|
167
|
+
Nevertheless you might want to have a better unobtrusiveness for your javascript, meaning
|
168
|
+
you want to be able to wrap the forms yourself with your nice layout.
|
169
|
+
That is also valuable if you want to have no javascript at all.
|
170
|
+
|
171
|
+
This is exactly what the option `_no_wrap` is for. Basically if you want that,
|
172
|
+
it is better to have your Backend middleware before the API in the Rack stack:
|
173
|
+
|
174
|
+
map '/' do
|
175
|
+
run Frontend
|
176
|
+
end
|
177
|
+
|
178
|
+
map '/admin' do
|
179
|
+
use Rack::Auth::Basic, "your-realm" do |username, password|
|
180
|
+
[username, password] == ['username', 'password']
|
181
|
+
end
|
182
|
+
use Backend
|
183
|
+
run BackendAPI
|
184
|
+
end
|
185
|
+
|
186
|
+
Then what you do is that you make your Backend middleware aware that if the GET param
|
187
|
+
`_no_wrap` is used, it has to forward the request and then wrap the body:
|
188
|
+
|
189
|
+
class Backend
|
190
|
+
def initialize(app); @app = app; end
|
191
|
+
def call(env)
|
192
|
+
if Rack::Request.new(env)['_no_wrap']
|
193
|
+
status, header, body = @app.call(env)
|
194
|
+
res = Rack::Response.new('<!-- ', status, header)
|
195
|
+
if body.respond_to? :to_str
|
196
|
+
res.write body.to_str
|
197
|
+
elsif body.respond_to?(:each)
|
198
|
+
body.each { |part|
|
199
|
+
res.write part.to_s
|
200
|
+
}
|
201
|
+
end
|
202
|
+
res.write(' -->')
|
203
|
+
res.finish
|
204
|
+
else
|
205
|
+
[200, {'Content-Type'=>'text/plain'}, ['not wrapped']]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
Here, if the param `_no_wrap` is used, this middleware will ask the response to the API middleware
|
211
|
+
and then will create a new Response with the body wrapped between `<!-- ` and ` -->`.
|
212
|
+
|
167
213
|
HOW TO PLUG AN ORM
|
168
214
|
==================
|
169
215
|
|
@@ -204,6 +250,7 @@ CHANGE LOG
|
|
204
250
|
0.0.1 First version
|
205
251
|
0.0.2 Accept CamelCased class names
|
206
252
|
0.0.3 Fix Form mockup
|
253
|
+
0.0.4 Partial available not only via XHR but also via `_no_wrap` param
|
207
254
|
|
208
255
|
COPYRIGHT
|
209
256
|
=========
|
data/lib/backend_api.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class BackendAPI
|
2
|
-
VERSION = [0,0,
|
2
|
+
VERSION = [0,0,4]
|
3
3
|
WRAP = <<-EOT
|
4
4
|
<!doctype html>
|
5
5
|
<html>
|
@@ -51,7 +51,7 @@ class BackendAPI
|
|
51
51
|
def get
|
52
52
|
@model_instance ||= @model_class.backend_post
|
53
53
|
@model_instance.backend_put @req['model']
|
54
|
-
form = @model_instance.backend_form(@req.path, @req['fields'], :destination => @req['_destination'], :submit_text => @req['_submit_text'] )
|
54
|
+
form = @model_instance.backend_form(@req.path, @req['fields'], :destination => @req['_destination'], :submit_text => @req['_submit_text'], :no_wrap => @req['_no_wrap'])
|
55
55
|
@res.write(wrap_form(form))
|
56
56
|
end
|
57
57
|
|
@@ -102,14 +102,14 @@ class BackendAPI
|
|
102
102
|
@res.redirect(::Rack::Utils::unescape(@req['_destination']))
|
103
103
|
end
|
104
104
|
else
|
105
|
-
form = @model_instance.backend_form(@req.path, @req['model'].keys, :destination => @req['_destination'], :submit_text => @req['_submit_text'])
|
105
|
+
form = @model_instance.backend_form(@req.path, @req['model'].keys, :destination => @req['_destination'], :submit_text => @req['_submit_text'], :no_wrap => @req['_no_wrap'])
|
106
106
|
@res.write(wrap_form(form))
|
107
107
|
@res.status=400 # Bad Request
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
111
|
def wrap_form(form)
|
112
|
-
if @req.xhr?
|
112
|
+
if @req['_no_wrap'] || @req.xhr?
|
113
113
|
form
|
114
114
|
else
|
115
115
|
WRAP % [@model_class_name, form]
|
@@ -27,6 +27,7 @@ module ::Sequel::Plugins::RackBackendApiAdapter
|
|
27
27
|
o << "<input type='hidden' name='_method' value='#{opts[:method] || method}' />\n"
|
28
28
|
o << "<input type='hidden' name='_destination' value='#{opts[:destination]}' />\n" unless opts[:destination].nil?
|
29
29
|
o << "<input type='hidden' name='_submit_text' value='#{opts[:submit_text]}' />\n" unless opts[:submit_text].nil?
|
30
|
+
o << "<input type='hidden' name='_no_wrap' value='#{opts[:no_wrap]}' />\n" unless opts[:no_wrap].nil?
|
30
31
|
o << "<input type='submit' name='save' value='#{opts[:submit_text] || 'SAVE'}' />\n"
|
31
32
|
o << "</form>\n"
|
32
33
|
o
|
data/rack-backend-api.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'rack-backend-api'
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.4"
|
4
4
|
s.platform = Gem::Platform::RUBY
|
5
5
|
s.summary = "A Rack middleware that provides a simple API for your Admin section"
|
6
6
|
s.description = "The purpose of this Rack Middleware is to provide an API that interfaces with database actions in order to build a CMS."
|
data/test/spec_backend_api.rb
CHANGED
@@ -22,6 +22,27 @@ def wrap(title, form) #mock wrapped versions of forms when not XHR
|
|
22
22
|
BackendAPI::WRAP % [title,form]
|
23
23
|
end
|
24
24
|
|
25
|
+
class WrappingMiddleware
|
26
|
+
def initialize(app); @app = app; end
|
27
|
+
def call(env)
|
28
|
+
if Rack::Request.new(env)['_no_wrap']
|
29
|
+
status, header, body = @app.call(env)
|
30
|
+
res = Rack::Response.new('<!-- ', status, header)
|
31
|
+
if body.respond_to? :to_str
|
32
|
+
res.write body.to_str
|
33
|
+
elsif body.respond_to?(:each)
|
34
|
+
body.each { |part|
|
35
|
+
res.write part.to_s
|
36
|
+
}
|
37
|
+
end
|
38
|
+
res.write(' -->')
|
39
|
+
res.finish
|
40
|
+
else
|
41
|
+
[200, {'Content-Type'=>'text/plain'}, ['not wrapped']]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
25
46
|
describe 'API Misc' do
|
26
47
|
should "Send 404 X-cascade if no response at the bottom of the Rack stack - Builder::run" do
|
27
48
|
res = req_lint(BackendAPI.new).get('/zzz')
|
@@ -85,9 +106,16 @@ describe 'API Post' do
|
|
85
106
|
res.headers['Location']=='http://www.domain.com/list.xml'
|
86
107
|
Haiku.order(:id).last.title.should=='Destination Summer'
|
87
108
|
end
|
88
|
-
should "
|
109
|
+
should "Keep _destination until form is validated" do
|
89
110
|
req_lint(BackendAPI.new).post('/haiku', :params => {'_destination' => '/', 'model' => {'title' => '13'}}).body.should.match(/name='_destination'.*value='\/'/)
|
90
111
|
end
|
112
|
+
should "Keep _no_wrap until form is validated" do
|
113
|
+
compared = Haiku.new.set('title' => '13')
|
114
|
+
compared.valid?
|
115
|
+
res = req_lint(WrappingMiddleware.new(BackendAPI.new)).post('/haiku', :params => {'_no_wrap' => 'true', 'model' => {'title' => '13'}})
|
116
|
+
res.body.should==('<!-- '+compared.backend_form('/haiku',['title'], {:no_wrap=>'true'})+' -->')
|
117
|
+
res.body.should.match(/name='_no_wrap'.*value='true'/)
|
118
|
+
end
|
91
119
|
end
|
92
120
|
|
93
121
|
describe 'API Get' do
|
@@ -106,8 +134,10 @@ describe 'API Get' do
|
|
106
134
|
req_lint(BackendAPI.new).get('/haiku', :params => {'model' => update}).body.should==wrap('Haiku', Haiku.new.set(update).backend_form('/haiku'))
|
107
135
|
req_lint(BackendAPI.new).get('/haiku/3', :params => {'model' => update}).body.should==wrap('Haiku', Haiku[3].set(update).backend_form('/haiku/3'))
|
108
136
|
end
|
109
|
-
should "Return a partial if the request is XHR" do
|
137
|
+
should "Return a partial if the request is XHR or param _no_wrap is used" do
|
110
138
|
req_lint(BackendAPI.new).get('/haiku', "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest").body.should==Haiku.new.backend_form('/haiku')
|
139
|
+
req_lint(BackendAPI.new).get('/haiku?_no_wrap=true').body.should==Haiku.new.backend_form('/haiku', nil, {:no_wrap=>'true'})
|
140
|
+
req_lint(WrappingMiddleware.new(BackendAPI.new)).get('/haiku?_no_wrap=true').body.should==('<!-- '+Haiku.new.backend_form('/haiku', nil, {:no_wrap=>'true'})+' -->')
|
111
141
|
end
|
112
142
|
end
|
113
143
|
|
@@ -149,6 +179,13 @@ describe 'API Put' do
|
|
149
179
|
should "keep destination until form is validated" do
|
150
180
|
req_lint(BackendAPI.new).put('/haiku/3', :params => {'_destination' => '/', 'model' => {'title' => '13'}}).body.should.match(/name='_destination'.*value='\/'/)
|
151
181
|
end
|
182
|
+
should "Keep _no_wrap until form is validated" do
|
183
|
+
compared = Haiku[3].set('title' => '13')
|
184
|
+
compared.valid?
|
185
|
+
res = req_lint(WrappingMiddleware.new(BackendAPI.new)).post('/haiku/3', :params => {'_no_wrap' => 'true', 'model' => {'title' => '13'}})
|
186
|
+
res.body.should==('<!-- '+compared.backend_form('/haiku/3',['title'], {:no_wrap=>'true'})+' -->')
|
187
|
+
res.body.should.match(/name='_no_wrap'.*value='true'/)
|
188
|
+
end
|
152
189
|
end
|
153
190
|
|
154
191
|
describe 'API Delete' do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-backend-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Mickael Riga
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-21 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|