grape 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grape might be problematic. Click here for more details.

data/CHANGELOG.md CHANGED
@@ -1,8 +1,34 @@
1
+ 0.5.0 (6/14/2013)
2
+ =================
3
+
4
+ #### Features
5
+
6
+ * [#344](https://github.com/intridea/grape/pull/344): Added `parser :type, nil` which disables input parsing for a given content-type - [@dblock](https://github.com/dblock).
7
+ * [#381](https://github.com/intridea/grape/issues/381): Added `cascade false` option at API level to remove the `X-Cascade: true` header from the API response - [@dblock](https://github.com/dblock).
8
+ * [#392](https://github.com/intridea/grape/pull/392): Extracted headers and params from `Endpoint` to `Grape::Request` - [@niedhui](https://github.com/niedhui).
9
+ * [#376](https://github.com/intridea/grape/pull/376): Added `route_param`, syntax sugar for quick declaration of route parameters - [@mbleigh](https://github.com/mbleigh).
10
+ * [#390](https://github.com/intridea/grape/pull/390): Added default value for an `optional` parameter - [@oivoodoo](https://github.com/oivoodoo).
11
+ * [#403](https://github.com/intridea/grape/pull/403): Added support for versioning using the `Accept-Version` header - [@politician](https://github.com/politician).
12
+ * [#407](https://github.com/intridea/grape/issues/407): Specifying `default_format` will also set the default POST/PUT data parser to the given format - [@dblock](https://github.com/dblock).
13
+ * [#241](https://github.com/intridea/grape/issues/241): Present with multiple entities using an optional Symbol - [@niedhui](https://github.com/niedhui).
14
+
15
+ #### Fixes
16
+
17
+ * [#378](https://github.com/intridea/grape/pull/378): Fix: stop rescuing all exceptions during formatting - [@kbarrette](https://github.com/kbarrette).
18
+ * [#380](https://github.com/intridea/grape/pull/380): Fix: `Formatter#read_body_input` when transfer encoding is chunked - [@paulnicholon](https://github.com/paulnicholson).
19
+ * [#347](https://github.com/intridea/grape/issues/347): Fix: handling non-hash body params - [@paulnicholon](https://github.com/paulnicholson).
20
+ * [#394](https://github.com/intridea/grape/pull/394): Fix: path version no longer overwrites a `version` parameter - [@tmornini](https://github.com/tmornini).
21
+ * [#412](https://github.com/intridea/grape/issues/412): Fix: specifying `content_type` will also override the selection of the data formatter - [@dblock](https://github.com/dblock).
22
+ * [#383](https://github.com/intridea/grape/issues/383): Fix: Mounted APIs aren't inheriting settings (including `before` and `after` filters) - [@seanmoon](https://github.com/seanmoon).
23
+ * [#408](https://github.com/intridea/grape/pull/408): Fix: Goliath passes request header keys as symbols not strings - [@bobek](https://github.com/bobek).
24
+ * [#417](https://github.com/intridea/grape/issues/417): Fix: Rails 4 does not rewind input, causes POSTed data to be empty - [@dblock](https://github.com/dblock).
25
+ * [#423](https://github.com/intridea/grape/pull/423): Fix: `Grape::Endpoint#declared` now correctly handles nested params (ie. declared with `group`) - [@jbarreneche](https://github.com/jbarreneche).
26
+ * [#427](https://github.com/intridea/grape/issues/427): Fix: `declared(params)` breaks when `params` contains array - [@timhabermaas](https://github.com/timhabermaas)
27
+
1
28
  0.4.1 (4/1/2013)
2
29
  ================
3
30
 
4
31
  * [#375](https://github.com/intridea/grape/pull/375): Fix: throwing an `:error` inside a middleware doesn't respect the `format` settings - [@dblock](https://github.com/dblock).
5
- * Your contribution here.
6
32
 
7
33
  0.4.0 (3/17/2013)
8
34
  =================
@@ -101,8 +127,7 @@
101
127
  0.2.2
102
128
  =====
103
129
 
104
- Features
105
- --------
130
+ #### Features
106
131
 
107
132
  * [#201](https://github.com/intridea/grape/pull/201), [#236](https://github.com/intridea/grape/pull/236), [#221](https://github.com/intridea/grape/pull/221): Added coercion and validations support to `params` DSL - [@schmurfy](https://github.com/schmurfy), [@tim-vandecasteele](https://github.com/tim-vandecasteele), [@adamgotterer](https://github.com/adamgotterer).
108
133
  * [#204](https://github.com/intridea/grape/pull/204): Added ability to declare shared `params` at `namespace` level - [@tim-vandecasteele](https://github.com/tim-vandecasteele).
@@ -110,8 +135,7 @@ Features
110
135
  * [#240](https://github.com/intridea/grape/pull/240): Define API response format from a query string `format` parameter, if specified - [@neetiraj](https://github.com/neetiraj).
111
136
  * Adds Endpoint#declared to easily filter out unexpected params. - [@mbleigh](https://github.com/mbleigh)
112
137
 
113
- Fixes
114
- -----
138
+ #### Fixes
115
139
 
116
140
  * [#248](https://github.com/intridea/grape/pull/248): Fix: API `version` returns last version set - [@narkoz](https://github.com/narkoz).
117
141
  * [#242](https://github.com/intridea/grape/issues/242): Fix: permanent redirect status should be `301`, was `304` - [@adamgotterer](https://github.com/adamgotterer).
data/Gemfile CHANGED
@@ -15,4 +15,5 @@ group :development, :test do
15
15
  gem 'github-markup'
16
16
  gem 'cookiejar'
17
17
  gem 'rack-contrib'
18
+ gem 'redcarpet', :platforms => :ruby
18
19
  end
data/README.md CHANGED
@@ -10,13 +10,9 @@ content negotiation, versioning and much more.
10
10
 
11
11
  [![Build Status](https://travis-ci.org/intridea/grape.png?branch=master)](http://travis-ci.org/intridea/grape) [![Code Climate](https://codeclimate.com/github/intridea/grape.png)](https://codeclimate.com/github/intridea/grape)
12
12
 
13
- ## Stable Release
13
+ ## Project Resources
14
14
 
15
- You're reading the documentation for the stable 0.4.1 release of Grape.
16
-
17
- ## Project Tracking
18
-
19
- * [Grape Google Group](http://groups.google.com/group/ruby-grape)
15
+ * Need help? [Grape Google Group](http://groups.google.com/group/ruby-grape)
20
16
  * [Grape Wiki](https://github.com/intridea/grape/wiki)
21
17
 
22
18
  ## Installation
@@ -41,7 +37,7 @@ the context of recreating parts of the Twitter API.
41
37
  module Twitter
42
38
  class API < Grape::API
43
39
 
44
- version 'v1', :using => :header, :vendor => 'twitter'
40
+ version 'v1', using: :header, vendor: 'twitter'
45
41
  format :json
46
42
 
47
43
  helpers do
@@ -69,40 +65,42 @@ module Twitter
69
65
 
70
66
  desc "Return a status."
71
67
  params do
72
- requires :id, :type => Integer, :desc => "Status id."
68
+ requires :id, type: Integer, desc: "Status id."
73
69
  end
74
- get ':id' do
75
- Status.find(params[:id])
70
+ route_param :id do
71
+ get do
72
+ Status.find(params[:id])
73
+ end
76
74
  end
77
75
 
78
76
  desc "Create a status."
79
77
  params do
80
- requires :status, :type => String, :desc => "Your status."
78
+ requires :status, type: String, desc: "Your status."
81
79
  end
82
80
  post do
83
81
  authenticate!
84
82
  Status.create!({
85
- :user => current_user,
86
- :text => params[:status]
83
+ user: current_user,
84
+ text: params[:status]
87
85
  })
88
86
  end
89
87
 
90
88
  desc "Update a status."
91
89
  params do
92
- requires :id, :type => String, :desc => "Status ID."
93
- requires :status, :type => String, :desc => "Your status."
90
+ requires :id, type: String, desc: "Status ID."
91
+ requires :status, type: String, desc: "Your status."
94
92
  end
95
93
  put ':id' do
96
94
  authenticate!
97
95
  current_user.statuses.find(params[:id]).update({
98
- :user => current_user,
99
- :text => params[:status]
96
+ user: current_user,
97
+ text: params[:status]
100
98
  })
101
99
  end
102
100
 
103
101
  desc "Delete a status."
104
102
  params do
105
- requires :id, :type => String, :desc => "Status ID."
103
+ requires :id, type: String, desc: "Status ID."
106
104
  end
107
105
  delete ':id' do
108
106
  authenticate!
@@ -136,12 +134,39 @@ And would respond to the following routes:
136
134
 
137
135
  Grape will also automatically respond to HEAD and OPTIONS for all GET, and just OPTIONS for all other routes.
138
136
 
137
+ ### Alongside Sinatra (or other frameworks)
138
+
139
+ If you wish to mount Grape alongside another Rack framework such as Sinatra, you can do so easily using
140
+ `Rack::Cascade`:
141
+
142
+ ```ruby
143
+ # Example config.ru
144
+
145
+ require 'sinatra'
146
+ require 'grape'
147
+
148
+ class API < Grape::API
149
+ get :hello do
150
+ {hello: "world"}
151
+ end
152
+ end
153
+
154
+ class Web < Sinatra::Base
155
+ get '/' do
156
+ "Hello world."
157
+ end
158
+ end
159
+
160
+ use Rack::Session::Cookie
161
+ run Rack::Cascade.new [API, Web]
162
+ ```
163
+
139
164
  ### Rails
140
165
 
141
166
  Place API files into `app/api` and modify `application.rb`.
142
167
 
143
168
  ```ruby
144
- config.paths.add "app/api", :glob => "**/*.rb"
169
+ config.paths.add "app/api", glob: "**/*.rb"
145
170
  config.autoload_paths += Dir["#{Rails.root}/app/api/*"]
146
171
  ```
147
172
 
@@ -175,13 +200,13 @@ end
175
200
 
176
201
  ## Versioning
177
202
 
178
- There are three strategies in which clients can reach your API's endpoints: `:path`,
179
- `:header` and `:param`. The default strategy is `:path`.
203
+ There are four strategies in which clients can reach your API's endpoints: `:path`,
204
+ `:header`, `:accept_version_header` and `:param`. The default strategy is `:path`.
180
205
 
181
206
  ### Path
182
207
 
183
208
  ```ruby
184
- version 'v1', :using => :path
209
+ version 'v1', using: :path
185
210
  ```
186
211
 
187
212
  Using this versioning strategy, clients should pass the desired version in the URL.
@@ -191,7 +216,7 @@ Using this versioning strategy, clients should pass the desired version in the U
191
216
  ### Header
192
217
 
193
218
  ```ruby
194
- version 'v1', :using => :header, :vendor => 'twitter'
219
+ version 'v1', using: :header, vendor: 'twitter'
195
220
  ```
196
221
 
197
222
  Using this versioning strategy, clients should pass the desired version in the HTTP `Accept` head.
@@ -203,10 +228,25 @@ supplied. This behavior is similar to routing in Rails. To circumvent this defau
203
228
  one could use the `:strict` option. When this option is set to `true`, a `406 Not Acceptable` error
204
229
  is returned when no correct `Accept` header is supplied.
205
230
 
231
+ ### Accept-Version Header
232
+
233
+ ```ruby
234
+ version 'v1', using: :accept_version_header
235
+ ```
236
+
237
+ Using this versioning strategy, clients should pass the desired version in the HTTP `Accept-Version` header.
238
+
239
+ curl -H "Accept-Version=v1" http://localhost:9292/statuses/public_timeline
240
+
241
+ By default, the first matching version is used when no `Accept-Version` header is
242
+ supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
243
+ one could use the `:strict` option. When this option is set to `true`, a `406 Not Acceptable` error
244
+ is returned when no correct `Accept` header is supplied.
245
+
206
246
  ### Param
207
247
 
208
248
  ```ruby
209
- version 'v1', :using => :param
249
+ version 'v1', using: :param
210
250
  ```
211
251
 
212
252
  Using this versioning strategy, clients should pass the desired version as a request parameter,
@@ -217,7 +257,7 @@ either in the URL query string or in the request body.
217
257
  The default name for the query parameter is 'apiver' but can be specified using the `:parameter` option.
218
258
 
219
259
  ```ruby
220
- version 'v1', :using => :param, :parameter => "v"
260
+ version 'v1', using: :param, parameter: "v"
221
261
  ```
222
262
 
223
263
  curl -H http://localhost:9292/statuses/public_timeline?v=v1
@@ -258,7 +298,7 @@ The Grape endpoint:
258
298
 
259
299
  ```ruby
260
300
  post '/statuses' do
261
- Status.create!({ :text => params[:text] })
301
+ Status.create!({ text: params[:text] })
262
302
  end
263
303
  ```
264
304
 
@@ -298,6 +338,14 @@ end
298
338
  When a type is specified an implicit validation is done after the coercion to ensure
299
339
  the output type is the one declared.
300
340
 
341
+ Optional parameters can have a default value.
342
+
343
+ ```ruby
344
+ params do
345
+ optional :color, type: String, default: 'blue'
346
+ end
347
+ ```
348
+
301
349
  Parameters can be nested using `group`. In the above example, this means
302
350
  `params[:media][:url]` is required along with `params[:id]`.
303
351
 
@@ -331,7 +379,7 @@ The `namespace` method has a number of aliases, including: `group`, `resource`,
331
379
  class AlphaNumeric < Grape::Validations::Validator
332
380
  def validate_param!(attr_name, params)
333
381
  unless params[attr_name] =~ /^[[:alnum:]]+$/
334
- throw :error, :status => 400, :message => "#{attr_name}: must consist of alpha-numeric characters"
382
+ throw :error, status: 400, message: "#{attr_name}: must consist of alpha-numeric characters"
335
383
  end
336
384
  end
337
385
  end
@@ -339,7 +387,7 @@ end
339
387
 
340
388
  ```ruby
341
389
  params do
342
- requires :text, :alpha_numeric => true
390
+ requires :text, alpha_numeric: true
343
391
  end
344
392
  ```
345
393
 
@@ -349,7 +397,7 @@ You can also create custom classes that take parameters.
349
397
  class Length < Grape::Validations::SingleOptionValidator
350
398
  def validate_param!(attr_name, params)
351
399
  unless params[attr_name].length <= @option
352
- throw :error, :status => 400, :message => "#{attr_name}: must be at the most #{@option} characters long"
400
+ throw :error, status: 400, message: "#{attr_name}: must be at the most #{@option} characters long"
353
401
  end
354
402
  end
355
403
  end
@@ -357,7 +405,7 @@ end
357
405
 
358
406
  ```ruby
359
407
  params do
360
- requires :text, :length => 140
408
+ requires :text, length: 140
361
409
  end
362
410
  ```
363
411
 
@@ -405,11 +453,11 @@ Optionally, you can define requirements for your named route parameters using re
405
453
  expressions on namespace or endpoint. The route will match only if all requirements are met.
406
454
 
407
455
  ```ruby
408
- get ':id', :requirements => { :id => /[0-9]*/ } do
456
+ get ':id', requirements: { id: /[0-9]*/ } do
409
457
  Status.find(params[:id])
410
458
  end
411
459
 
412
- namespace :outer, :requirements => { :id => /[0-9]*/ } do
460
+ namespace :outer, requirements: { id: /[0-9]*/ } do
413
461
  get :id do
414
462
  end
415
463
 
@@ -458,11 +506,11 @@ class API < Grape::API
458
506
  get 'status_count' do
459
507
  cookies[:status_count] ||= 0
460
508
  cookies[:status_count] += 1
461
- { :status_count => cookies[:status_count] }
509
+ { status_count: cookies[:status_count] }
462
510
  end
463
511
 
464
512
  delete 'status_count' do
465
- { :status_count => cookies.delete(:status_count) }
513
+ { status_count: cookies.delete(:status_count) }
466
514
  end
467
515
 
468
516
  end
@@ -472,10 +520,10 @@ Use a hash-based syntax to set more than one value.
472
520
 
473
521
  ```ruby
474
522
  cookies[:status_count] = {
475
- :value => 0,
476
- :expires => Time.tomorrow,
477
- :domain => '.twitter.com',
478
- :path => '/'
523
+ value: 0,
524
+ expires: Time.tomorrow,
525
+ domain: '.twitter.com',
526
+ path: '/'
479
527
  }
480
528
 
481
529
  cookies[:status_count][:value] +=1
@@ -490,7 +538,7 @@ cookies.delete :status_count
490
538
  Specify an optional path.
491
539
 
492
540
  ```ruby
493
- cookies.delete :status_count, :path => '/'
541
+ cookies.delete :status_count, path: '/'
494
542
  ```
495
543
 
496
544
  ## Redirecting
@@ -502,7 +550,7 @@ redirect "/statuses"
502
550
  ```
503
551
 
504
552
  ```ruby
505
- redirect "/statuses", :permanent => true
553
+ redirect "/statuses", permanent: true
506
554
  ```
507
555
 
508
556
  ## Allowed Methods
@@ -531,15 +579,15 @@ include an "Allow" header listing the supported methods.
531
579
  class API < Grape::API
532
580
 
533
581
  get '/rt_count' do
534
- { :rt_count => current_user.rt_count }
582
+ { rt_count: current_user.rt_count }
535
583
  end
536
584
 
537
585
  params do
538
- requires :value, :type => Integer, :desc => 'Value to add to the rt count.'
586
+ requires :value, type: Integer, desc: 'Value to add to the rt count.'
539
587
  end
540
588
  put '/rt_count' do
541
589
  current_user.rt_count += params[:value].to_i
542
- { :rt_count => current_user.rt_count }
590
+ { rt_count: current_user.rt_count }
543
591
  end
544
592
 
545
593
  end
@@ -634,7 +682,7 @@ automatically sets the default error code and content-type.
634
682
  ```ruby
635
683
  class Twitter::API < Grape::API
636
684
  rescue_from :all do |e|
637
- rack_response({ :message => "rescued from #{e.class.name}" })
685
+ rack_response({ message: "rescued from #{e.class.name}" })
638
686
  end
639
687
  end
640
688
  ```
@@ -665,19 +713,23 @@ end
665
713
 
666
714
  #### Rails 3.x
667
715
 
668
- When mounted inside Rails 3.x, errors like "404 Not Found" or "406 Not Acceptable" will likely be
669
- handled and rendered by Rails handlers. For instance, accessing a nonexistent route "/api/foo"
670
- raises a 404, which inside rails will ultimately be translated to an `ActionController::RoutingError`,
671
- which most likely will get rendered to a HTML error page.
716
+ When mounted inside containers, such as Rails 3.x, errors like "404 Not Found" or
717
+ "406 Not Acceptable" will likely be handled and rendered by Rails handlers. For instance,
718
+ accessing a nonexistent route "/api/foo" raises a 404, which inside rails will ultimately
719
+ be translated to an `ActionController::RoutingError`, which most likely will get rendered
720
+ to a HTML error page.
672
721
 
673
- Most APIs will enjoy avoiding Rails exceptions and have their own exceptions reaching the client.
674
- In that case, the `:cascade` option can be set to `false` on the versioning definition.
722
+ Most APIs will enjoy preventing downstream handlers from handling errors. You may set the
723
+ `:cascade` option to `false` for the entire API or separately on specific `version` definitions,
724
+ which will remove the `X-Cascade: true` header from API responses.
675
725
 
676
726
  ```ruby
677
- version 'v1', :using => :header, :vendor => 'twitter', :cascade => false
727
+ cascade false
678
728
  ```
679
729
 
680
- The `:cascade` option can also be used with the other versioning strategies (`:param` and `:path`).
730
+ ```ruby
731
+ version 'v1', using: :header, vendor: 'twitter', cascade: false
732
+ ```
681
733
 
682
734
  ## Logging
683
735
 
@@ -742,6 +794,16 @@ class Twitter::API < Grape::API
742
794
  end
743
795
  ```
744
796
 
797
+ When the content-type is omitted, Grape will return a 406 error code unless `default_format` is specified.
798
+ The following API will try to parse any data without a content-type using a JSON parser.
799
+
800
+ ```ruby
801
+ class Twitter::API < Grape::API
802
+ format :json
803
+ default_format :json
804
+ end
805
+ ```
806
+
745
807
  If you combine `format` with `rescue_from :all`, errors will be rendered using the same format.
746
808
  If you do not want this behavior, set the default error formatter with `default_error_formatter`.
747
809
 
@@ -822,23 +884,21 @@ end
822
884
  ### CORS
823
885
 
824
886
  Grape supports CORS via [Rack::CORS](https://github.com/cyu/rack-cors), part of the
825
- [rack-cors](https://github.com/cyu/rack-cors) gem. Add `rack-cors` to your `Gemfile`.
887
+ [rack-cors](https://github.com/cyu/rack-cors) gem. Add `rack-cors` to your `Gemfile`,
888
+ then use the middleware in your config.ru file.
826
889
 
827
890
  ```ruby
828
891
  require 'rack/cors'
829
892
 
830
- class API < Grape::API
831
- use Rack::Cors do
832
- allow do
833
- origins '*'
834
- resource '*', :headers => :any, :methods => :get
835
- end
836
- end
837
- format :json
838
- get '/' do
839
- 'Hello World'
893
+ use Rack::Cors do
894
+ allow do
895
+ origins '*'
896
+ resource '*', headers: :any, methods: :get
840
897
  end
841
898
  end
899
+
900
+ run Twitter::API
901
+
842
902
  ```
843
903
 
844
904
  ## Content-type
@@ -871,7 +931,7 @@ to `:value`. The parameter will be available via `params[:value]` inside the API
871
931
  ```ruby
872
932
  module CustomParser
873
933
  def self.call(object, env)
874
- { :value => object.to_s }
934
+ { value: object.to_s }
875
935
  end
876
936
  end
877
937
  ```
@@ -892,6 +952,8 @@ You can invoke the above API as follows.
892
952
  curl -X PUT -d 'data' 'http://localhost:9292/value' -H Content-Type:text/custom -v
893
953
  ```
894
954
 
955
+ You can disable parsing for a content-type with `nil`. For example, `parser :json, nil` will disable JSON parsing altogether. The request data is then available as-is in `env['api.request.body']`.
956
+
895
957
  ## RESTful Model Representations
896
958
 
897
959
  Grape supports a range of ways to present your data with some help from a generic `present` method,
@@ -900,8 +962,8 @@ hash may include `:with`, which defines the entity to expose.
900
962
 
901
963
  ### Grape Entities
902
964
 
903
- Add the [grape-entity](https://github.com/agileanimal/grape-entity) gem to your Gemfile.
904
- Please refer to the [grape-entity documentation](https://github.com/agileanimal/grape-entity/blob/master/README.markdown)
965
+ Add the [grape-entity](https://github.com/intridea/grape-entity) gem to your Gemfile.
966
+ Please refer to the [grape-entity documentation](https://github.com/intridea/grape-entity/blob/master/README.markdown)
905
967
  for more details.
906
968
 
907
969
  The following example exposes statuses.
@@ -912,11 +974,11 @@ module API
912
974
  module Entities
913
975
  class Status < Grape::Entity
914
976
  expose :user_name
915
- expose :text, :documentation => { :type => "string", :desc => "Status update text." }
916
- expose :ip, :if => { :type => :full }
917
- expose :user_type, user_id, :if => lambda{ |status, options| status.user.public? }
977
+ expose :text, documentation: { type: "string", desc: "Status update text." }
978
+ expose :ip, if: { type: :full }
979
+ expose :user_type, user_id, if: lambda{ |status, options| status.user.public? }
918
980
  expose :digest { |status, options| Digest::MD5.hexdigest(status.txt) }
919
- expose :replies, :using => API::Status, :as => :replies
981
+ expose :replies, using: API::Status, as: :replies
920
982
  end
921
983
  end
922
984
 
@@ -924,17 +986,38 @@ module API
924
986
  version 'v1'
925
987
 
926
988
  desc 'Statuses index', {
927
- :object_fields => API::Entities::Status.documentation
989
+ object_fields: API::Entities::Status.documentation
928
990
  }
929
991
  get '/statuses' do
930
992
  statuses = Status.all
931
993
  type = current_user.admin? ? :full : :default
932
- present statuses, with: API::Entities::Status, :type => type
994
+ present statuses, with: API::Entities::Status, type: type
933
995
  end
934
996
  end
935
997
  end
936
998
  ```
937
999
 
1000
+ You can present with multiple entities using an optional Symbol argument.
1001
+
1002
+ ```ruby
1003
+ get '/statuses' do
1004
+ statuses = Status.all.page(1).per(20)
1005
+ present :total_page, 10
1006
+ present :per_page, 20
1007
+ present :statuses, statuses, with: API::Entities::Status
1008
+ end
1009
+ ```
1010
+
1011
+ The response will be
1012
+
1013
+ ```
1014
+ {
1015
+ total_page: 10,
1016
+ per_page: 20,
1017
+ statuses: []
1018
+ }
1019
+ ```
1020
+
938
1021
  In addition to separately organizing entities, it may be useful to put them as namespaced
939
1022
  classes underneath the model they represent.
940
1023
 
@@ -982,7 +1065,7 @@ end
982
1065
  ```
983
1066
 
984
1067
  ```ruby
985
- http_digest({ :realm => 'Test Api', :opaque => 'app secret' }) do |username|
1068
+ http_digest({ realm: 'Test Api', opaque: 'app secret' }) do |username|
986
1069
  # lookup the user's password here
987
1070
  { 'user1' => 'password1' }[username]
988
1071
  end
@@ -1017,7 +1100,7 @@ call with `route`.
1017
1100
  class MyAPI < Grape::API
1018
1101
  desc "Returns a description of a parameter."
1019
1102
  params do
1020
- requires :id, :type => Integer, :desc => "Identity."
1103
+ requires :id, type: Integer, desc: "Identity."
1021
1104
  end
1022
1105
  get "params/:id" do
1023
1106
  route.route_params[params[:id]] # yields the parameter description
@@ -1057,7 +1140,7 @@ should match from start to end to match, otherwise a `404 Not Found` is
1057
1140
  returned. However, this is sometimes not what you want, because it is not always
1058
1141
  known upfront what can be expected from the call. This is because Rack-mount by
1059
1142
  default anchors requests to match from the start to the end, or not at all.
1060
- Rails solves this problem by using a `:anchor => false` option in your routes.
1143
+ Rails solves this problem by using a `anchor: false` option in your routes.
1061
1144
  In Grape this option can be used as well when a method is defined.
1062
1145
 
1063
1146
  For instance when you're API needs to get part of an URL, for instance:
@@ -1065,7 +1148,7 @@ For instance when you're API needs to get part of an URL, for instance:
1065
1148
  ```ruby
1066
1149
  class TwitterAPI < Grape::API
1067
1150
  namespace :statuses do
1068
- get '/(*:status)', :anchor => false do
1151
+ get '/(*:status)', anchor: false do
1069
1152
 
1070
1153
  end
1071
1154
  end
@@ -1144,8 +1227,8 @@ In Rails, HTTP request tests would go into the `spec/requests` group. You may wa
1144
1227
 
1145
1228
  ```ruby
1146
1229
  RSpec.configure do |config|
1147
- config.include RSpec::Rails::RequestExampleGroup, :type => :request, :example_group => {
1148
- :file_path => /spec\/api/
1230
+ config.include RSpec::Rails::RequestExampleGroup, type: :request, example_group: {
1231
+ file_path: /spec\/api/
1149
1232
  }
1150
1233
  end
1151
1234
  ```
@@ -1158,7 +1241,7 @@ Add API paths to `config/application.rb`.
1158
1241
 
1159
1242
  ```ruby
1160
1243
  # Auto-load API and its subdirectories
1161
- config.paths.add "app/api", :glob => "**/*.rb"
1244
+ config.paths.add "app/api", glob: "**/*.rb"
1162
1245
  config.autoload_paths += Dir["#{Rails.root}/app/api/*"]
1163
1246
  ```
1164
1247
 
@@ -1166,6 +1249,9 @@ Create `config/initializers/reload_api.rb`.
1166
1249
 
1167
1250
  ```ruby
1168
1251
  if Rails.env.development?
1252
+
1253
+ ActiveSupport::Dependencies.explicitly_unloadable_constants << "Twitter::API"
1254
+
1169
1255
  api_files = Dir["#{Rails.root}/app/api/**/*.rb"]
1170
1256
  api_reloader = ActiveSupport::FileUpdateChecker.new(api_files) do
1171
1257
  Rails.application.reload_routes!
@@ -1173,6 +1259,7 @@ if Rails.env.development?
1173
1259
  ActionDispatch::Callbacks.to_prepare do
1174
1260
  api_reloader.execute_if_updated
1175
1261
  end
1262
+
1176
1263
  end
1177
1264
  ```
1178
1265
 
@@ -1181,7 +1268,9 @@ See [StackOverflow #3282655](http://stackoverflow.com/questions/3282655/ruby-on-
1181
1268
 
1182
1269
  ## Performance Monitoring
1183
1270
 
1184
- Grape integrates with NewRelic via the [newrelic-grape](https://github.com/flyerhzm/newrelic-grape) gem.
1271
+ Grape integrates with NewRelic via the
1272
+ [newrelic-grape](https://github.com/flyerhzm/newrelic-grape) gem, and
1273
+ with Librato Metrics with the [grape-librato](https://github.com/seanmoon/grape-librato) gem.
1185
1274
 
1186
1275
  ## Contributing to Grape
1187
1276