Skip to content

Commit a449fd4

Browse files
committed
Merge pull request ruby-grape#147 from dblock/frontier-default-format
Frontier: enable default_format to actually do something
2 parents d24bd2f + e61c905 commit a449fd4

File tree

7 files changed

+138
-65
lines changed

7 files changed

+138
-65
lines changed

README.markdown

Lines changed: 57 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ Grape APIs are Rack applications that are created by subclassing `Grape::API`.
3636
Below is a simple example showing some of the more common features of Grape in
3737
the context of recreating parts of the Twitter API.
3838

39-
```ruby
39+
``` ruby
4040
class Twitter::API < Grape::API
41-
version 'v1', :using => :header, :vendor => 'twitter', :format => :json
41+
version 'v1', :using => :header, :vendor => 'twitter'
4242

4343
helpers do
4444
def current_user
@@ -87,7 +87,7 @@ end
8787

8888
The above sample creates a Rack application that can be run from a rackup *config.ru* file:
8989

90-
```ruby
90+
``` ruby
9191
run Twitter::API
9292
```
9393
And would respond to the following routes:
@@ -99,22 +99,22 @@ And would respond to the following routes:
9999

100100
In a Rails application, modify *config/routes*:
101101

102-
```ruby
102+
``` ruby
103103
mount Twitter::API => "/"
104104
```
105105

106106
## Versioning
107107

108108
Versioning is handled with HTTP Accept head by default, but can be configures
109-
to [use different strategies](https://github.com/intridea/grape/wiki/API-Versioning).
109+
to [use different strategies](https://github.com/intridea/grape/wiki/API-Versioning).
110110
For example, to request the above with a version, you would make the following
111111
request:
112112

113113
curl -H Accept=application/vnd.twitter-v1+json http://localhost:9292/statuses/public_timeline
114114

115115
By default, the first matching version is used when no Accept header is
116-
supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
117-
one could use the `:strict` option. When this option is set to `true`, a `404 Not found` error
116+
supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
117+
one could use the `:strict` option. When this option is set to `true`, a `404 Not found` error
118118
is returned when no correct Accept header is supplied.
119119

120120
Serialization takes place automatically.
@@ -124,7 +124,7 @@ Serialization takes place automatically.
124124
You can define helper methods that your endpoints can use with the `helpers`
125125
macro by either giving a block or a module:
126126

127-
````ruby
127+
``` ruby
128128
module MyHelpers
129129
def say_hello(user)
130130
"hey there #{user.name}"
@@ -147,13 +147,13 @@ class API < Grape::API
147147
say_hello(current_user)
148148
end
149149
end
150-
````
150+
```
151151

152152
## Cookies
153153

154154
You can set, get and delete your cookies very simply using `cookies` method:
155155

156-
````ruby
156+
``` ruby
157157
class API < Grape::API
158158
get '/counter' do
159159
cookies[:counter] ||= 0
@@ -165,32 +165,32 @@ class API < Grape::API
165165
{ :result => cookies.delete(:counter) }
166166
end
167167
end
168-
````
168+
```
169169

170170
To set more than value use hash-based syntax:
171171

172-
````ruby
172+
``` ruby
173173
cookies[:counter] = {
174174
:value => 0,
175175
:expires => Time.tomorrow,
176176
:domain => '.example.com',
177177
:path => '/'
178178
}
179179
cookies[:counter][:value] +=1
180-
````
180+
```
181181

182182
## Raising Errors
183183

184184
You can raise errors explicitly.
185185

186-
```ruby
186+
``` ruby
187187
error!("Access Denied", 401)
188188
```
189189

190190
You can also return JSON formatted objects explicitly by raising error! and
191191
passing a hash instead of a message.
192192

193-
```ruby
193+
``` ruby
194194
error!({ "error" => "unexpected error", "detail" => "missing widget" }, 500)
195195
```
196196

@@ -199,15 +199,15 @@ error!({ "error" => "unexpected error", "detail" => "missing widget" }, 500)
199199
Grape can be told to rescue all exceptions and instead return them in
200200
text or json formats.
201201

202-
```ruby
202+
``` ruby
203203
class Twitter::API < Grape::API
204204
rescue_from :all
205205
end
206206
```
207207

208208
You can also rescue specific exceptions.
209209

210-
```ruby
210+
``` ruby
211211
class Twitter::API < Grape::API
212212
rescue_from ArgumentError, NotImplementedError
213213
end
@@ -216,7 +216,7 @@ end
216216
The error format can be specified using `error_format`. Available formats are
217217
`:json` and `:txt` (default).
218218

219-
```ruby
219+
``` ruby
220220
class Twitter::API < Grape::API
221221
error_format :json
222222
end
@@ -225,7 +225,7 @@ end
225225
You can rescue all exceptions with a code block. The `rack_response` wrapper
226226
automatically sets the default error code and content-type.
227227

228-
```ruby
228+
``` ruby
229229
class Twitter::API < Grape::API
230230
rescue_from :all do |e|
231231
rack_response({ :message => "rescued from #{e.class.name}" })
@@ -236,43 +236,60 @@ end
236236
You can also rescue specific exceptions with a code block and handle the Rack
237237
response at the lowest level.
238238

239-
```ruby
239+
``` ruby
240240
class Twitter::API < Grape::API
241241
rescue_from :all do |e|
242242
Rack::Response.new([ e.message ], 500, { "Content-type" => "text/error" }).finish
243243
end
244244
end
245245
```
246246

247-
class Twitter::API < Grape::API
248-
rescue_from ArgumentError do |e|
249-
Rack::Response.new([ "ArgumentError: #{e.message}" ], 500)
250-
end
251-
rescue_from NotImplementedError do |e|
252-
Rack::Response.new([ "NotImplementedError: #{e.message}" ], 500)
253-
end
254-
end
247+
``` ruby
248+
class Twitter::API < Grape::API
249+
rescue_from ArgumentError do |e|
250+
Rack::Response.new([ "ArgumentError: #{e.message}" ], 500)
251+
end
252+
rescue_from NotImplementedError do |e|
253+
Rack::Response.new([ "NotImplementedError: #{e.message}" ], 500)
254+
end
255+
end
256+
```
255257

256258
## Content-Types
257259

258-
By default, Grape supports _XML_, _JSON_, _Atom_, _RSS_, and _text_ content-types.
259-
Your API can declare additional types to support. Response format is determined by the
260+
By default, Grape supports _XML_, _JSON_, _Atom_, _RSS_, and _text_ content-types.
261+
Your API can declare additional types to support. Response format is determined by the
260262
request's extension or `Accept` header.
261263

262-
```ruby
264+
``` ruby
263265
class Twitter::API < Grape::API
264266
content_type :xls, "application/vnd.ms-excel"
265267
end
266268
```
267269

270+
You can also set the default format. The order for choosing the format is the following.
271+
272+
* Use the file extension, if specified. If the file is .json, choose the JSON format.
273+
* Use the format, if specified by the `format` option.
274+
* Attempt to find an acceptable format from the `Accept` header.
275+
* Use the default format, if specified by the `default_format` option.
276+
* Default to `:txt` otherwise.
277+
278+
``` ruby
279+
class Twitter::API < Grape::API
280+
format :json
281+
default_format :json
282+
end
283+
```
284+
268285
## Writing Tests
269286

270287
You can test a Grape API with RSpec. Tests make HTTP requests, therefore they
271288
must go into the `spec/request` group. You may want your API code to go into
272289
`app/api` - you can match that layout under `spec` by adding the following in
273290
`spec/spec_helper.rb`.
274291

275-
```ruby
292+
``` ruby
276293
RSpec.configure do |config|
277294
config.include RSpec::Rails::RequestExampleGroup, :type => :request, :example_group => {
278295
:file_path => /spec\/api/
@@ -282,7 +299,7 @@ end
282299

283300
A simple RSpec API test makes a `get` request and parses the response.
284301

285-
```ruby
302+
``` ruby
286303
require 'spec_helper'
287304

288305
describe Twitter::API do
@@ -299,10 +316,10 @@ end
299316
## Describing and Inspecting an API
300317

301318
Grape lets you add a description to an API along with any other optional
302-
elements that can also be inspected at runtime.
319+
elements that can also be inspected at runtime.
303320
This can be useful for generating documentation.
304321

305-
```ruby
322+
``` ruby
306323
class TwitterAPI < Grape::API
307324

308325
version 'v1'
@@ -327,7 +344,7 @@ contains a `route_prefix`, `route_version`, `route_namespace`, `route_method`,
327344
follows the API path may contain any number of keys and its values are also
328345
accessible via dynamically-generated `route_[name]` functions.
329346

330-
```ruby
347+
``` ruby
331348
TwitterAPI::versions # yields [ 'v1', 'v2' ]
332349
TwitterAPI::routes # yields an array of Grape::Route objects
333350
TwitterAPI::routes[0].route_version # yields 'v1'
@@ -336,7 +353,7 @@ TwitterAPI::routes[0].route_description # yields [ { "s" => { :desc => "string t
336353

337354
Parameters can also be tagged to the method declaration itself.
338355

339-
```ruby
356+
``` ruby
340357
class StringAPI < Grape::API
341358
get "split/:string", { :params => [ "token" ], :optional_params => [ "limit" ] } do
342359
params[:string].split(params[:token], (params[:limit] || 0))
@@ -349,7 +366,7 @@ StringAPI::routes[0].route_optional_params # yields an array [ "limit" ]
349366

350367
It's possible to retrieve the information about the current route from within an API call with `route`.
351368

352-
```ruby
369+
``` ruby
353370
class MyAPI < Grape::API
354371
desc "Returns a description of a parameter.", { :params => { "id" => "a required id" } }
355372
get "params/:id" do
@@ -372,7 +389,7 @@ In Grape this option can be used as well when a method is defined.
372389

373390
For instance when you're API needs to get part of an URL, for instance:
374391

375-
```ruby
392+
``` ruby
376393
class UrlAPI < Grape::API
377394
namespace :urls do
378395
get '/(*:url)', :anchor => false do
@@ -403,5 +420,5 @@ MIT License. See LICENSE for details.
403420

404421
## Copyright
405422

406-
Copyright (c) 2010-2012 Michael Bleigh and Intridea, Inc.
423+
Copyright (c) 2010-2012 Michael Bleigh and Intridea, Inc.
407424

lib/grape/api.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,18 @@ def desc(description, options = {})
109109
@last_description = options.merge(:description => description)
110110
end
111111

112-
# Specify the default format for the API's
113-
# serializers. Currently only `:json` is
114-
# supported.
112+
# Specify the default format for the API's serializers.
113+
# May be `:json` or `:txt` (default).
115114
def default_format(new_format = nil)
116115
new_format ? set(:default_format, new_format.to_sym) : settings[:default_format]
117116
end
118117

118+
# Specify the format for the API's serializers.
119+
# May be `:json` or `:txt`.
120+
def format(new_format = nil)
121+
new_format ? set(:format, new_format.to_sym) : settings[:format]
122+
end
123+
119124
# Specify the format for error messages.
120125
# May be `:json` or `:txt` (default).
121126
def error_format(new_format = nil)

lib/grape/endpoint.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,10 @@ def build_middleware
273273
:version_options => settings[:version_options]
274274
}
275275
end
276-
276+
277277
b.use Grape::Middleware::Formatter,
278-
:default_format => settings[:default_format] || :json,
278+
:format => settings[:format],
279+
:default_format => settings[:default_format] || :txt,
279280
:content_types => settings[:content_types]
280281

281282
aggregate_setting(:middleware).each do |m|

lib/grape/middleware/formatter.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class Formatter < Base
66
include Formats
77

88
def default_options
9-
{
9+
{
1010
:default_format => :txt,
1111
:formatters => {},
1212
:content_types => {},
@@ -19,7 +19,7 @@ def headers
1919
end
2020

2121
def before
22-
fmt = format_from_extension || format_from_header || options[:default_format]
22+
fmt = format_from_extension || options[:format] || format_from_header || options[:default_format]
2323
if content_types.key?(fmt)
2424
if !env['rack.input'].nil? and (body = env['rack.input'].read).strip.length != 0
2525
parser = parser_for fmt
@@ -52,7 +52,7 @@ def format_from_extension
5252
end
5353

5454
def format_from_header
55-
mime_array.each do |t|
55+
mime_array.each do |t|
5656
if mime_types.key?(t)
5757
return mime_types[t]
5858
end

0 commit comments

Comments
 (0)