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.
- data/.yardopts +2 -0
- data/CHANGELOG.markdown +19 -0
- data/Gemfile +2 -0
- data/README.markdown +166 -131
- data/Rakefile +1 -3
- data/lib/grape.rb +0 -3
- data/lib/grape/api.rb +16 -4
- data/lib/grape/cookies.rb +32 -30
- data/lib/grape/endpoint.rb +25 -11
- data/lib/grape/entity.rb +5 -0
- data/lib/grape/error_formatter/base.rb +2 -1
- data/lib/grape/middleware/base.rb +9 -2
- data/lib/grape/middleware/error.rb +11 -11
- data/lib/grape/middleware/formatter.rb +8 -5
- data/lib/grape/middleware/versioner/header.rb +1 -3
- data/lib/grape/middleware/versioner/path.rb +15 -2
- data/lib/grape/util/deep_merge.rb +4 -4
- data/lib/grape/validations.rb +2 -3
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +316 -175
- data/spec/grape/endpoint_spec.rb +159 -57
- data/spec/grape/entity_spec.rb +80 -80
- data/spec/grape/middleware/auth/basic_spec.rb +3 -3
- data/spec/grape/middleware/auth/digest_spec.rb +4 -4
- data/spec/grape/middleware/auth/oauth2_spec.rb +4 -4
- data/spec/grape/middleware/base_spec.rb +9 -9
- data/spec/grape/middleware/error_spec.rb +4 -4
- data/spec/grape/middleware/exception_spec.rb +13 -13
- data/spec/grape/middleware/formatter_spec.rb +25 -25
- data/spec/grape/middleware/versioner/header_spec.rb +23 -23
- data/spec/grape/middleware/versioner/param_spec.rb +8 -8
- data/spec/grape/middleware/versioner/path_spec.rb +8 -8
- data/spec/grape/middleware/versioner_spec.rb +6 -3
- data/spec/grape/util/hash_stack_spec.rb +20 -20
- data/spec/grape/validations/presence_spec.rb +1 -1
- data/spec/grape/validations/regexp_spec.rb +2 -2
- data/spec/grape/validations_spec.rb +4 -4
- data/spec/shared/versioning_examples.rb +48 -20
- metadata +5 -7
- data/.document +0 -5
- data/lib/grape/middleware/prefixer.rb +0 -21
- data/spec/grape/middleware/prefixer_spec.rb +0 -30
data/.yardopts
ADDED
data/CHANGELOG.markdown
CHANGED
@@ -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
data/README.markdown
CHANGED
@@ -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
|
-
```
|
42
|
-
|
43
|
-
|
44
|
-
format :json
|
36
|
+
```ruby
|
37
|
+
module Twitter
|
38
|
+
class API < Grape::API
|
45
39
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
52
|
-
|
48
|
+
def authenticate!
|
49
|
+
error!('401 Unauthorized', 401) unless current_user
|
50
|
+
end
|
53
51
|
end
|
54
|
-
end
|
55
52
|
|
56
|
-
|
53
|
+
resource :statuses do
|
57
54
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
55
|
+
desc "Return a public timeline."
|
56
|
+
get :public_timeline do
|
57
|
+
Status.limit(20)
|
58
|
+
end
|
62
59
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
60
|
+
desc "Return a personal timeline."
|
61
|
+
get :home_timeline do
|
62
|
+
authenticate!
|
63
|
+
current_user.statuses.limit(20)
|
64
|
+
end
|
68
65
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
229
|
+
The request:
|
233
230
|
|
234
|
-
```
|
231
|
+
```
|
232
|
+
curl -d '{"text": "140 characters"}' 'http://localhost:9292/statuses' -H Content-Type:application/json -v
|
233
|
+
```
|
235
234
|
|
236
|
-
The Grape
|
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
|
-
|
347
|
-
|
345
|
+
content_type = header['Content-type']
|
346
|
+
# ...
|
348
347
|
end
|
349
348
|
```
|
350
349
|
|
351
350
|
```ruby
|
352
351
|
get do
|
353
|
-
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
447
|
+
```ruby
|
437
448
|
redirect "/statuses"
|
438
449
|
```
|
439
450
|
|
440
|
-
```
|
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
|
-
```
|
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
|
-
```
|
494
|
-
error!
|
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
|
-
```
|
501
|
-
error!
|
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
|
518
|
+
Grape can be told to rescue all exceptions and return them in the API format.
|
507
519
|
|
508
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
##
|
639
|
+
## API Formats
|
628
640
|
|
629
|
-
By default, Grape supports _XML_, _JSON_,
|
630
|
-
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
|
671
|
-
supports multiple formats with `format`.
|
692
|
+
Built-in formats are the following.
|
672
693
|
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
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
|
-
|
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
|
-
```
|
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
|
715
|
+
* Default to `:txt`.
|
702
716
|
|
703
717
|
## Content-type
|
704
718
|
|
705
|
-
You can override the content-type of the response
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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
|
-
```
|
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(
|
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
|
-
```
|
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
|
-
*
|
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
|