forked from sinatra/sinatra.github.com
/
sinatra-respond-with.html
88 lines (72 loc) · 2.73 KB
/
sinatra-respond-with.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<h1>Sinatra::RespondWith</h1>
<p>This extensions lets Sinatra automatically choose what template to render
or action to perform depending on the request's Accept header.</p>
<p>Example:</p>
<pre># Without Sinatra::RespondWith
get '/' do
data = { :name => 'example' }
request.accept.each do |type|
case type
when 'text/html'
halt haml(:index, :locals => data)
when 'text/json'
halt data.to_json
when 'application/atom+xml'
halt nokogiri(:'index.atom', :locals => data)
when 'application/xml', 'text/xml'
halt nokogiri(:'index.xml', :locals => data)
when 'text/plain'
halt 'just an example'
end
end
error 406
end
# With Sinatra::RespondWith
get '/' do
respond_with :index, :name => 'example' do |f|
f.txt { 'just an example' }
end
end</pre>
<p>Both helper methods <tt>respond_to</tt> and <tt>respond_with</tt> let you
define custom handlers like the one above for <tt>text/plain</tt>.
<tt>respond_with</tt> additionally takes a template name and/or an object
to offer the following default behavior:</p>
<ul><li>
<p>If a template name is given, search for a template called
<tt>name.format.engine</tt> (<tt>index.xml.nokogiri</tt> in the above
example).</p>
</li><li>
<p>If a template name is given, search for a templated called
<tt>name.engine</tt> for engines known to result in the requested format
(<tt>index.haml</tt>).</p>
</li><li>
<p>If a file extension associated with the mime type is known to Sinatra, and
the object responds to <tt>to_extension</tt>, call that method and use the
result (<tt>data.to_json</tt>).</p>
</li></ul>
<h2>Security</h2>
<p>Since methods are triggered based on client input, this can lead to
security issues (but not as seviere as those might apear in the first
place: keep in mind that only known file extensions are used). You
therefore should limit the possible formats you serve.</p>
<p>This is possible with the <tt>provides</tt> condition:</p>
<pre>get '/', :provides => [:html, :json, :xml, :atom] do
respond_with :index, :name => 'example'
end</pre>
<p>However, since you have to set <tt>provides</tt> for every route, this
extension adds a app global (class method) `respond_to`, that let's you
define content types for all routes:</p>
<pre>respond_to :html, :json, :xml, :atom
get('/a') { respond_with :index, :name => 'a' }
get('/b') { respond_with :index, :name => 'b' }</pre>
<h2>Custom Types</h2>
<p>Use the <tt>on</tt> method for defining actions for custom types:</p>
<pre>get '/' do
respond_to do |f|
f.xml { nokogiri :index }
f.on('application/custom') { custom_action }
f.on('text/*') { data.to_s }
f.on('*/*') { "matches everything" }
end
end</pre>
<p>Definition order does not matter.</p>