grape 0.2.3 → 0.2.4

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.

Files changed (42) hide show
  1. data/.yardopts +2 -0
  2. data/CHANGELOG.markdown +19 -0
  3. data/Gemfile +2 -0
  4. data/README.markdown +166 -131
  5. data/Rakefile +1 -3
  6. data/lib/grape.rb +0 -3
  7. data/lib/grape/api.rb +16 -4
  8. data/lib/grape/cookies.rb +32 -30
  9. data/lib/grape/endpoint.rb +25 -11
  10. data/lib/grape/entity.rb +5 -0
  11. data/lib/grape/error_formatter/base.rb +2 -1
  12. data/lib/grape/middleware/base.rb +9 -2
  13. data/lib/grape/middleware/error.rb +11 -11
  14. data/lib/grape/middleware/formatter.rb +8 -5
  15. data/lib/grape/middleware/versioner/header.rb +1 -3
  16. data/lib/grape/middleware/versioner/path.rb +15 -2
  17. data/lib/grape/util/deep_merge.rb +4 -4
  18. data/lib/grape/validations.rb +2 -3
  19. data/lib/grape/version.rb +1 -1
  20. data/spec/grape/api_spec.rb +316 -175
  21. data/spec/grape/endpoint_spec.rb +159 -57
  22. data/spec/grape/entity_spec.rb +80 -80
  23. data/spec/grape/middleware/auth/basic_spec.rb +3 -3
  24. data/spec/grape/middleware/auth/digest_spec.rb +4 -4
  25. data/spec/grape/middleware/auth/oauth2_spec.rb +4 -4
  26. data/spec/grape/middleware/base_spec.rb +9 -9
  27. data/spec/grape/middleware/error_spec.rb +4 -4
  28. data/spec/grape/middleware/exception_spec.rb +13 -13
  29. data/spec/grape/middleware/formatter_spec.rb +25 -25
  30. data/spec/grape/middleware/versioner/header_spec.rb +23 -23
  31. data/spec/grape/middleware/versioner/param_spec.rb +8 -8
  32. data/spec/grape/middleware/versioner/path_spec.rb +8 -8
  33. data/spec/grape/middleware/versioner_spec.rb +6 -3
  34. data/spec/grape/util/hash_stack_spec.rb +20 -20
  35. data/spec/grape/validations/presence_spec.rb +1 -1
  36. data/spec/grape/validations/regexp_spec.rb +2 -2
  37. data/spec/grape/validations_spec.rb +4 -4
  38. data/spec/shared/versioning_examples.rb +48 -20
  39. metadata +5 -7
  40. data/.document +0 -5
  41. data/lib/grape/middleware/prefixer.rb +0 -21
  42. data/spec/grape/middleware/prefixer_spec.rb +0 -30
@@ -0,0 +1,2 @@
1
+ --markup-provider=redcarpet
2
+ --markup=markdown
@@ -1,3 +1,22 @@
1
+ 0.2.4 (01/06/2013)
2
+ ==================
3
+
4
+ * [#297](https://github.com/intridea/grape/issues/297): Added `default_error_formatter` - [@dblock](https://github.com/dblock).
5
+ * [#297](https://github.com/intridea/grape/issues/297): Setting `format` will automatically set `default_error_formatter` - [@dblock](https://github.com/dblock).
6
+ * [#295](https://github.com/intridea/grape/issues/295): Storing original API source block in endpoint's `source` attribute - [@dblock](https://github.com/dblock).
7
+ * [#293](https://github.com/intridea/grape/pull/293): Added options to `cookies.delete`, enables passing a path - [@inst](https://github.com/inst).
8
+ * [#174](https://github.com/intridea/grape/issues/174): The value of `env['PATH_INFO']` is no longer altered with `path` versioning - [@dblock](https://github.com/dblock).
9
+ * [#296](https://github.com/intridea/grape/issues/296): Fix: ArgumentError with default error formatter - [@dblock](https://github.com/dblock).
10
+ * [#298](https://github.com/intridea/grape/pull/298): Fix: subsequent calls to `body_params` would fail due to IO read - [@justinmcp](https://github.com/justinmcp).
11
+ * [#301](https://github.com/intridea/grape/issues/301): Fix: symbol memory leak in cookie and formatter middleware - [@dblock](https://github.com/dblock).
12
+ * [#300](https://github.com/intridea/grape/issues/300): Fix `Grape::API.routes` to include mounted api routes - [@aiwilliams](https://github.com/aiwilliams).
13
+ * [#302](https://github.com/intridea/grape/pull/302): Fix: removed redundant `autoload` entries - [@ugisozols](https://github.com/ugisozols).
14
+ * [#172](https://github.com/intridea/grape/issues/172): Fix: MultiJson deprecated methods warnings - [@dblock](https://github.com/dblock).
15
+ * [#133](https://github.com/intridea/grape/issues/133): Fix: header-based versioning with use of `prefix` - [@seanmoon](https://github.com/seanmoon), [@dblock](https://github.com/dblock).
16
+ * [#280](https://github.com/intridea/grape/issues/280): Fix: grouped parameters mangled in `route_params` hash - [@marcusg](https://github.com/marcusg), [@dblock](https://github.com/dblock).
17
+ * [#304](https://github.com/intridea/grape/issues/304): Fix: `present x, :with => Entity` returns class references with `format :json` - [@dblock](https://github.com/dblock).
18
+ * [#196](https://github.com/intridea/grape/issues/196): Fix: root requests don't work with `prefix` - [@dblock](https://github.com/dblock).
19
+
1
20
  0.2.3 (24/12/2012)
2
21
  ==================
3
22
 
data/Gemfile CHANGED
@@ -12,4 +12,6 @@ group :development, :test do
12
12
  gem 'json'
13
13
  gem 'rspec'
14
14
  gem 'rack-test', "~> 0.6.2", :require => "rack/test"
15
+ gem 'github-markup'
16
+ gem 'redcarpet'
15
17
  end
@@ -15,11 +15,6 @@ content negotiation, versioning and much more.
15
15
  * [Grape Google Group](http://groups.google.com/group/ruby-grape)
16
16
  * [Grape Wiki](https://github.com/intridea/grape/wiki)
17
17
 
18
- ## Stable Release
19
-
20
- You're reading the documentation for the next release of Grape, which should be 0.2.3.
21
- The current stable release is [0.2.2](https://github.com/intridea/grape/blob/v0.2.2/README.markdown).
22
-
23
18
  ## Installation
24
19
 
25
20
  Grape is available as a gem, to install it just install the gem:
@@ -38,78 +33,80 @@ Grape APIs are Rack applications that are created by subclassing `Grape::API`.
38
33
  Below is a simple example showing some of the more common features of Grape in
39
34
  the context of recreating parts of the Twitter API.
40
35
 
41
- ``` ruby
42
- class Twitter::API < Grape::API
43
- version 'v1', :using => :header, :vendor => 'twitter'
44
- format :json
36
+ ```ruby
37
+ module Twitter
38
+ class API < Grape::API
45
39
 
46
- helpers do
47
- def current_user
48
- @current_user ||= User.authorize!(env)
49
- end
40
+ version 'v1', :using => :header, :vendor => 'twitter'
41
+ format :json
42
+
43
+ helpers do
44
+ def current_user
45
+ @current_user ||= User.authorize!(env)
46
+ end
50
47
 
51
- def authenticate!
52
- error!('401 Unauthorized', 401) unless current_user
48
+ def authenticate!
49
+ error!('401 Unauthorized', 401) unless current_user
50
+ end
53
51
  end
54
- end
55
52
 
56
- resource :statuses do
53
+ resource :statuses do
57
54
 
58
- desc "Return a public timeline."
59
- get :public_timeline do
60
- Status.limit(20)
61
- end
55
+ desc "Return a public timeline."
56
+ get :public_timeline do
57
+ Status.limit(20)
58
+ end
62
59
 
63
- desc "Return a personal timeline."
64
- get :home_timeline do
65
- authenticate!
66
- current_user.statuses.limit(20)
67
- end
60
+ desc "Return a personal timeline."
61
+ get :home_timeline do
62
+ authenticate!
63
+ current_user.statuses.limit(20)
64
+ end
68
65
 
69
- desc "Return a status."
70
- params do
71
- requires :id, :type => Integer, :desc => "Status id."
72
- end
73
- get ':id' do
74
- Status.find(params[:id])
75
- end
66
+ desc "Return a status."
67
+ params do
68
+ requires :id, :type => Integer, :desc => "Status id."
69
+ end
70
+ get ':id' do
71
+ Status.find(params[:id])
72
+ end
76
73
 
77
- desc "Create a status."
78
- params do
79
- requires :status, :type => String, :desc => "Your status."
80
- end
81
- post do
82
- authenticate!
83
- Status.create!({
84
- :user => current_user,
85
- :text => params[:status]
86
- })
87
- end
74
+ desc "Create a status."
75
+ params do
76
+ requires :status, :type => String, :desc => "Your status."
77
+ end
78
+ post do
79
+ authenticate!
80
+ Status.create!({
81
+ :user => current_user,
82
+ :text => params[:status]
83
+ })
84
+ end
88
85
 
89
- desc "Update a status."
90
- params do
91
- requires :id, :type => String, :desc => "Status ID."
92
- requires :status, :type => String, :desc => "Your status."
93
- end
94
- put ':id' do
95
- authenticate!
96
- current_user.statuses.find(params[:id]).update({
97
- :user => current_user,
98
- :text => params[:status]
99
- })
100
- end
86
+ desc "Update a status."
87
+ params do
88
+ requires :id, :type => String, :desc => "Status ID."
89
+ requires :status, :type => String, :desc => "Your status."
90
+ end
91
+ put ':id' do
92
+ authenticate!
93
+ current_user.statuses.find(params[:id]).update({
94
+ :user => current_user,
95
+ :text => params[:status]
96
+ })
97
+ end
101
98
 
102
- desc "Delete a status."
103
- params do
104
- requires :id, :type => String, :desc => "Status ID."
105
- end
106
- delete ':id' do
107
- authenticate!
108
- current_user.statuses.find(params[:id]).destroy
109
- end
99
+ desc "Delete a status."
100
+ params do
101
+ requires :id, :type => String, :desc => "Status ID."
102
+ end
103
+ delete ':id' do
104
+ authenticate!
105
+ current_user.statuses.find(params[:id]).destroy
106
+ end
110
107
 
108
+ end
111
109
  end
112
-
113
110
  end
114
111
  ```
115
112
 
@@ -120,7 +117,7 @@ end
120
117
  The above sample creates a Rack application that can be run from a rackup *config.ru* file
121
118
  with `rackup`:
122
119
 
123
- ``` ruby
120
+ ```ruby
124
121
  run Twitter::API
125
122
  ```
126
123
 
@@ -137,8 +134,8 @@ And would respond to the following routes:
137
134
 
138
135
  In a Rails application, modify *config/routes*:
139
136
 
140
- ``` ruby
141
- mount Twitter::API => "/"
137
+ ```ruby
138
+ mount Twitter::API
142
139
  ```
143
140
 
144
141
  Note that when using Rails you will need to restart the server to pick up changes in your API classes
@@ -178,7 +175,7 @@ is returned when no correct `Accept` header is supplied.
178
175
 
179
176
  ### Path
180
177
 
181
- ``` ruby
178
+ ```ruby
182
179
  version 'v1', :using => :path
183
180
  ```
184
181
 
@@ -209,7 +206,7 @@ version 'v1', :using => :param, :parameter => "v"
209
206
 
210
207
  You can add a description to API methods and namespaces.
211
208
 
212
- ``` ruby
209
+ ```ruby
213
210
  desc "Returns your public timeline."
214
211
  get :public_timeline do
215
212
  Status.limit(20)
@@ -229,11 +226,13 @@ end
229
226
 
230
227
  Parameters are also populated from the request body on POST and PUT for JSON and XML content-types.
231
228
 
232
- The Request:
229
+ The request:
233
230
 
234
- ```curl -d '{"text": "140 characters"}' 'http://localhost:9292/statuses' -H Content-Type:application/json -v```
231
+ ```
232
+ curl -d '{"text": "140 characters"}' 'http://localhost:9292/statuses' -H Content-Type:application/json -v
233
+ ```
235
234
 
236
- The Grape Endpoint:
235
+ The Grape endpoint:
237
236
 
238
237
  ```ruby
239
238
  post '/statuses' do
@@ -343,15 +342,15 @@ Headers are available through the `header` helper or the `env` hash object.
343
342
 
344
343
  ```ruby
345
344
  get do
346
- content_type = header['Content-type']
347
- ...
345
+ content_type = header['Content-type']
346
+ # ...
348
347
  end
349
348
  ```
350
349
 
351
350
  ```ruby
352
351
  get do
353
- error!('Unauthorized', 401) unless env['HTTP_SECRET_PASSWORD'] == 'swordfish'
354
- ...
352
+ error!('Unauthorized', 401) unless env['HTTP_SECRET_PASSWORD'] == 'swordfish'
353
+ # ...
355
354
  end
356
355
  ```
357
356
 
@@ -371,7 +370,7 @@ end
371
370
  You can define helper methods that your endpoints can use with the `helpers`
372
371
  macro by either giving a block or a module.
373
372
 
374
- ``` ruby
373
+ ```ruby
375
374
  module StatusHelpers
376
375
  def user_info(user)
377
376
  "#{user} has statused #{user.statuses} status(s)"
@@ -400,7 +399,7 @@ end
400
399
 
401
400
  You can set, get and delete your cookies very simply using `cookies` method.
402
401
 
403
- ``` ruby
402
+ ```ruby
404
403
  class API < Grape::API
405
404
 
406
405
  get 'status_count' do
@@ -418,7 +417,7 @@ end
418
417
 
419
418
  Use a hash-based syntax to set more than one value.
420
419
 
421
- ``` ruby
420
+ ```ruby
422
421
  cookies[:status_count] = {
423
422
  :value => 0,
424
423
  :expires => Time.tomorrow,
@@ -429,15 +428,27 @@ cookies[:status_count] = {
429
428
  cookies[:status_count][:value] +=1
430
429
  ```
431
430
 
431
+ Delete a cookie with `delete`.
432
+
433
+ ```ruby
434
+ cookies.delete :status_count
435
+ ```
436
+
437
+ Specify an optional path.
438
+
439
+ ```ruby
440
+ cookies.delete :status_count, :path => '/'
441
+ ```
442
+
432
443
  ## Redirecting
433
444
 
434
445
  You can redirect to a new url temporarily (302) or permanently (301).
435
446
 
436
- ``` ruby
447
+ ```ruby
437
448
  redirect "/statuses"
438
449
  ```
439
450
 
440
- ``` ruby
451
+ ```ruby
441
452
  redirect "/statuses", :permanent => true
442
453
  ```
443
454
 
@@ -447,7 +458,7 @@ When you add a route for a resource, a route for the HTTP OPTIONS
447
458
  method will also be added. The response to an OPTIONS request will
448
459
  include an "Allow" header listing the supported methods.
449
460
 
450
- ``` ruby
461
+ ```ruby
451
462
  class API < Grape::API
452
463
 
453
464
  get '/rt_count' do
@@ -461,6 +472,7 @@ class API < Grape::API
461
472
  current_user.rt_count += params[:value].to_i
462
473
  { :rt_count => current_user.rt_count }
463
474
  end
475
+
464
476
  end
465
477
  ```
466
478
 
@@ -490,22 +502,22 @@ curl -X DELETE -v http://localhost:3000/rt_count/
490
502
 
491
503
  You can abort the execution of an API method by raising errors with `error!`.
492
504
 
493
- ``` ruby
494
- error!("Access Denied", 401)
505
+ ```ruby
506
+ error! "Access Denied", 401
495
507
  ```
496
508
 
497
509
  You can also return JSON formatted objects by raising error! and passing a hash
498
510
  instead of a message.
499
511
 
500
- ``` ruby
501
- error!({ "error" => "unexpected error", "detail" => "missing widget" }, 500)
512
+ ```ruby
513
+ error! { "error" => "unexpected error", "detail" => "missing widget" }, 500
502
514
  ```
503
515
 
504
516
  ## Exception Handling
505
517
 
506
- Grape can be told to rescue all exceptions and return them in txt or json formats.
518
+ Grape can be told to rescue all exceptions and return them in the API format.
507
519
 
508
- ``` ruby
520
+ ```ruby
509
521
  class Twitter::API < Grape::API
510
522
  rescue_from :all
511
523
  end
@@ -513,7 +525,7 @@ end
513
525
 
514
526
  You can also rescue specific exceptions.
515
527
 
516
- ``` ruby
528
+ ```ruby
517
529
  class Twitter::API < Grape::API
518
530
  rescue_from ArgumentError, NotImplementedError
519
531
  end
@@ -523,7 +535,7 @@ The error format will match the request format. See "Content-Types" below.
523
535
 
524
536
  Custom error formatters for existing and additional types can be defined with a proc.
525
537
 
526
- ``` ruby
538
+ ```ruby
527
539
  class Twitter::API < Grape::API
528
540
  error_formatter :txt, lambda { |message, backtrace, options, env|
529
541
  "error: #{message} from #{backtrace}"
@@ -533,7 +545,7 @@ end
533
545
 
534
546
  You can also use a module or class.
535
547
 
536
- ``` ruby
548
+ ```ruby
537
549
  module CustomFormatter
538
550
  def self.call(message, backtrace, options, env)
539
551
  { message: message, backtrace: backtrace }
@@ -548,7 +560,7 @@ end
548
560
  You can rescue all exceptions with a code block. The `rack_response` wrapper
549
561
  automatically sets the default error code and content-type.
550
562
 
551
- ``` ruby
563
+ ```ruby
552
564
  class Twitter::API < Grape::API
553
565
  rescue_from :all do |e|
554
566
  rack_response({ :message => "rescued from #{e.class.name}" })
@@ -559,7 +571,7 @@ end
559
571
  You can also rescue specific exceptions with a code block and handle the Rack
560
572
  response at the lowest level.
561
573
 
562
- ``` ruby
574
+ ```ruby
563
575
  class Twitter::API < Grape::API
564
576
  rescue_from :all do |e|
565
577
  Rack::Response.new([ e.message ], 500, { "Content-type" => "text/error" }).finish
@@ -569,7 +581,7 @@ end
569
581
 
570
582
  Or rescue specific exceptions.
571
583
 
572
- ``` ruby
584
+ ```ruby
573
585
  class Twitter::API < Grape::API
574
586
  rescue_from ArgumentError do |e|
575
587
  Rack::Response.new([ "ArgumentError: #{e.message}" ], 500)
@@ -588,7 +600,7 @@ class from Ruby's standard library.
588
600
  To log messages from within an endpoint, you need to define a helper to make the logger
589
601
  available in the endpoint context.
590
602
 
591
- ``` ruby
603
+ ```ruby
592
604
  class API < Grape::API
593
605
  helpers do
594
606
  def logger
@@ -596,7 +608,7 @@ class API < Grape::API
596
608
  end
597
609
  end
598
610
  post '/statuses' do
599
- ...
611
+ # ...
600
612
  logger.info "#{current_user} has statused"
601
613
  end
602
614
  end
@@ -604,7 +616,7 @@ end
604
616
 
605
617
  You can also set your own logger.
606
618
 
607
- ``` ruby
619
+ ```ruby
608
620
  class MyLogger
609
621
  def warning(message)
610
622
  puts "this is a warning: #{message}"
@@ -624,10 +636,11 @@ class API < Grape::API
624
636
  end
625
637
  ```
626
638
 
627
- ## Content-Types
639
+ ## API Formats
628
640
 
629
- By default, Grape supports _XML_, _JSON_, _Atom_, _RSS_, and _text_ content-types.
630
- Serialization takes place automatically.
641
+ By default, Grape supports _XML_, _JSON_, and _TXT_ content-types. The default format is `:txt`.
642
+
643
+ Serialization takes place automatically. For example, you do not have to call `to_json` in each JSON API implementation.
631
644
 
632
645
  Your API can declare which types to support by using `content_type`. Response format
633
646
  is determined by the request's extension, an explicit `format` parameter in the query
@@ -636,16 +649,25 @@ string, or `Accept` header.
636
649
  The following API will only respond to the JSON content-type. All other requests will
637
650
  fail with an HTTP 406 error code.
638
651
 
639
- ``` ruby
652
+ ```ruby
640
653
  class Twitter::API < Grape::API
641
654
  format :json
642
655
  content_type :json, "application/json"
643
656
  end
644
657
  ```
645
658
 
659
+ If you combine `format` with `rescue_from :all`, errors will be rendered using the same format. If you do not want this behavior, set the default error formatter with `default_error_formatter`.
660
+
661
+ ```ruby
662
+ class Twitter::API < Grape::API
663
+ format :json
664
+ default_error_formatter :txt
665
+ end
666
+ ```
667
+
646
668
  Custom formatters for existing and additional types can be defined with a proc.
647
669
 
648
- ``` ruby
670
+ ```ruby
649
671
  class Twitter::API < Grape::API
650
672
  content_type :xls, "application/vnd.ms-excel"
651
673
  formatter :xls, lambda { |object, env| object.to_xls }
@@ -654,7 +676,7 @@ end
654
676
 
655
677
  You can also use a module or class.
656
678
 
657
- ``` ruby
679
+ ```ruby
658
680
  module XlsFormatter
659
681
  def self.call(object, env)
660
682
  object.to_xls
@@ -667,30 +689,22 @@ class Twitter::API < Grape::API
667
689
  end
668
690
  ```
669
691
 
670
- The default format is `:txt`. You can set the preferred format for an API that
671
- supports multiple formats with `format`.
692
+ Built-in formats are the following.
672
693
 
673
- ``` ruby
674
- class Twitter::API < Grape::API
675
- format :json
676
- end
677
- ```
694
+ * `:json`: use object's `to_json` when available, otherwise call `MultiJson.dump`
695
+ * `:xml`: use object's `to_xml` when available, usually via `MultiXml`, otherwise call `to_s`
696
+ * `:txt`: use object's `to_txt` when available, otherwise `to_s`
697
+ * `:serializable_hash`: use object's `serializable_hash` when available, otherwise fallback to `:json`
678
698
 
679
- You can set the fallback, default format with `default_format`.
699
+ Use `default_format` to set the fallback format when the format could not be determined from the `Accept` header.
700
+ See below for the order for choosing the API format.
680
701
 
681
- ``` ruby
702
+ ```ruby
682
703
  class Twitter::API < Grape::API
683
704
  default_format :json
684
705
  end
685
706
  ```
686
707
 
687
- Available formats are the following.
688
-
689
- * `:json`: use object's `to_json` when available, otherwise call `MultiJson.dump`
690
- * `:xml`: use object's `to_xml` when available, usually via `MultiXml`, otherwise call `to_s`
691
- * `:txt`: use object's `to_txt` when available, otherwise `to_s`
692
- * `:serializable_hash`: use object's `serializable_hash` when available, otherwise fallback to `:json`
693
-
694
708
  The order for choosing the format is the following.
695
709
 
696
710
  * Use the file extension, if specified. If the file is .json, choose the JSON format.
@@ -698,13 +712,14 @@ The order for choosing the format is the following.
698
712
  * Use the format set by the `format` option, if specified.
699
713
  * Attempt to find an acceptable format from the `Accept` header.
700
714
  * Use the default format, if specified by the `default_format` option.
701
- * Default to `:txt` otherwise.
715
+ * Default to `:txt`.
702
716
 
703
717
  ## Content-type
704
718
 
705
- You can override the content-type of the response by setting the `Content-Type` header.
719
+ Content-type is set by the formatter. You can override the content-type of the response at runtime
720
+ by setting the `Content-Type` header.
706
721
 
707
- ``` ruby
722
+ ```ruby
708
723
  class API < Grape::API
709
724
  get '/home_timeline_js' do
710
725
  content_type "application/javascript"
@@ -744,7 +759,7 @@ array.
744
759
  * expose the value returned by the block
745
760
  * block can only be applied to one exposure at a time
746
761
 
747
- ``` ruby
762
+ ```ruby
748
763
  module API
749
764
  module Entities
750
765
  class Status < Grape::Entity
@@ -794,7 +809,7 @@ options hash must always include `:with`, which defines the entity to expose.
794
809
 
795
810
  If the entity includes documentation it can be included in an endpoint's description.
796
811
 
797
- ``` ruby
812
+ ```ruby
798
813
  module API
799
814
  class Statuses < Grape::API
800
815
  version 'v1'
@@ -888,17 +903,19 @@ contains a `route_prefix`, `route_version`, `route_namespace`, `route_method`,
888
903
  follows the API path may contain any number of keys and its values are also
889
904
  accessible via dynamically-generated `route_[name]` functions.
890
905
 
891
- ``` ruby
906
+ ```ruby
892
907
  TwitterAPI::versions # yields [ 'v1', 'v2' ]
893
908
  TwitterAPI::routes # yields an array of Grape::Route objects
894
909
  TwitterAPI::routes[0].route_version # yields 'v1'
895
910
  TwitterAPI::routes[0].route_description # etc.
896
911
  ```
897
912
 
913
+ ## Current Route and Endpoint
914
+
898
915
  It's possible to retrieve the information about the current route from within an API
899
916
  call with `route`.
900
917
 
901
- ``` ruby
918
+ ```ruby
902
919
  class MyAPI < Grape::API
903
920
  desc "Returns a description of a parameter."
904
921
  params do
@@ -910,6 +927,21 @@ class MyAPI < Grape::API
910
927
  end
911
928
  ```
912
929
 
930
+ The current endpoint responding to the request is `self` within the API block
931
+ or `env['api.endpoint']` elsewhere. The endpoint has some interesting properties,
932
+ such as `source` which gives you access to the original code block of the API
933
+ implementation. This can be particularly useful for building a logger middleware.
934
+
935
+ ```ruby
936
+ class ApiLogger < Grape::Middleware::Base
937
+ def before
938
+ file = env['api.endpoint'].source.source_location[0]
939
+ line = env['api.endpoint'].source.source_location[1]
940
+ logger.debug "[api] #{file}:#{line}"
941
+ end
942
+ end
943
+ ```
944
+
913
945
  ## Anchoring
914
946
 
915
947
  Grape by default anchors all request paths, which means that the request URL
@@ -922,7 +954,7 @@ In Grape this option can be used as well when a method is defined.
922
954
 
923
955
  For instance when you're API needs to get part of an URL, for instance:
924
956
 
925
- ``` ruby
957
+ ```ruby
926
958
  class TwitterAPI < Grape::API
927
959
  namespace :statues do
928
960
  get '/(*:status)', :anchor => false do
@@ -962,7 +994,7 @@ describe Twitter::API do
962
994
  it "returns an empty array of statuses" do
963
995
  get "/api/v1/statuses"
964
996
  last_response.status.should == 200
965
- JSON.parse(response.body).should == []
997
+ JSON.parse(last_response.body).should == []
966
998
  end
967
999
  end
968
1000
  describe "GET /api/v1/statuses/:id" do
@@ -978,7 +1010,7 @@ end
978
1010
 
979
1011
  ### Writing Tests with Rails
980
1012
 
981
- ``` ruby
1013
+ ```ruby
982
1014
  require 'spec_helper'
983
1015
 
984
1016
  describe Twitter::API do
@@ -1009,6 +1041,9 @@ RSpec.configure do |config|
1009
1041
  }
1010
1042
  end
1011
1043
  ```
1044
+ ## Performance Monitoring
1045
+
1046
+ Grape integrates with NewRelic via the [newrelic-grape](https://github.com/flyerhzm/newrelic-grape) gem.
1012
1047
 
1013
1048
  ## Contributing to Grape
1014
1049
 
@@ -1018,7 +1053,7 @@ features and discuss issues.
1018
1053
  * Fork the project
1019
1054
  * Write tests for your new feature or a test that reproduces a bug
1020
1055
  * Implement your feature or make a bug fix
1021
- * Do not mess with Rakefile, version or history
1056
+ * Add a line to `CHANGELOG.markdown` describing your change
1022
1057
  * Commit, push and make a pull request. Bonus points for topic branches.
1023
1058
 
1024
1059
  ## License