grape 0.11.0 → 0.12.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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +23 -80
- data/.travis.yml +1 -1
- data/CHANGELOG.md +27 -0
- data/Gemfile +1 -1
- data/Guardfile +1 -1
- data/LICENSE +1 -1
- data/README.md +131 -30
- data/Rakefile +1 -1
- data/UPGRADING.md +110 -1
- data/gemfiles/rails_3.gemfile +1 -1
- data/gemfiles/rails_4.gemfile +1 -1
- data/grape.gemspec +4 -4
- data/lib/grape.rb +92 -62
- data/lib/grape/api.rb +10 -10
- data/lib/grape/cookies.rb +1 -1
- data/lib/grape/dsl/configuration.rb +7 -7
- data/lib/grape/dsl/helpers.rb +3 -3
- data/lib/grape/dsl/inside_route.rb +50 -21
- data/lib/grape/dsl/parameters.rb +25 -6
- data/lib/grape/dsl/request_response.rb +1 -1
- data/lib/grape/dsl/routing.rb +11 -10
- data/lib/grape/dsl/settings.rb +1 -1
- data/lib/grape/endpoint.rb +21 -19
- data/lib/grape/error_formatter/json.rb +1 -1
- data/lib/grape/exceptions/base.rb +1 -1
- data/lib/grape/exceptions/validation.rb +1 -1
- data/lib/grape/exceptions/validation_errors.rb +2 -2
- data/lib/grape/formatter/base.rb +1 -1
- data/lib/grape/formatter/json.rb +1 -1
- data/lib/grape/formatter/serializable_hash.rb +4 -4
- data/lib/grape/formatter/txt.rb +1 -1
- data/lib/grape/formatter/xml.rb +1 -1
- data/lib/grape/http/headers.rb +27 -0
- data/lib/grape/http/request.rb +1 -1
- data/lib/grape/middleware/error.rb +10 -4
- data/lib/grape/middleware/formatter.rb +13 -9
- data/lib/grape/middleware/globals.rb +2 -1
- data/lib/grape/middleware/versioner/accept_version_header.rb +2 -2
- data/lib/grape/middleware/versioner/header.rb +4 -4
- data/lib/grape/middleware/versioner/param.rb +2 -2
- data/lib/grape/middleware/versioner/path.rb +1 -1
- data/lib/grape/namespace.rb +2 -1
- data/lib/grape/parser/json.rb +1 -1
- data/lib/grape/parser/xml.rb +1 -1
- data/lib/grape/path.rb +3 -3
- data/lib/grape/presenters/presenter.rb +9 -0
- data/lib/grape/validations/params_scope.rb +3 -3
- data/lib/grape/validations/validators/allow_blank.rb +1 -1
- data/lib/grape/validations/validators/coerce.rb +6 -5
- data/lib/grape/validations/validators/default.rb +2 -2
- data/lib/grape/validations/validators/multiple_params_base.rb +1 -0
- data/lib/grape/validations/validators/regexp.rb +1 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/custom_validations_spec.rb +47 -0
- data/spec/grape/api/deeply_included_options_spec.rb +56 -0
- data/spec/grape/api_spec.rb +64 -42
- data/spec/grape/dsl/configuration_spec.rb +2 -2
- data/spec/grape/dsl/helpers_spec.rb +1 -1
- data/spec/grape/dsl/inside_route_spec.rb +75 -19
- data/spec/grape/dsl/parameters_spec.rb +59 -10
- data/spec/grape/dsl/request_response_spec.rb +62 -2
- data/spec/grape/dsl/routing_spec.rb +116 -18
- data/spec/grape/endpoint_spec.rb +57 -5
- data/spec/grape/entity_spec.rb +1 -1
- data/spec/grape/exceptions/body_parse_errors_spec.rb +5 -5
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +32 -32
- data/spec/grape/exceptions/validation_errors_spec.rb +1 -1
- data/spec/grape/integration/rack_spec.rb +4 -3
- data/spec/grape/middleware/auth/strategies_spec.rb +2 -2
- data/spec/grape/middleware/base_spec.rb +2 -2
- data/spec/grape/middleware/error_spec.rb +1 -1
- data/spec/grape/middleware/exception_spec.rb +5 -5
- data/spec/grape/middleware/formatter_spec.rb +10 -10
- data/spec/grape/middleware/globals_spec.rb +27 -0
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +1 -1
- data/spec/grape/middleware/versioner/header_spec.rb +1 -1
- data/spec/grape/middleware/versioner/param_spec.rb +1 -1
- data/spec/grape/middleware/versioner/path_spec.rb +1 -1
- data/spec/grape/path_spec.rb +6 -4
- data/spec/grape/presenters/presenter_spec.rb +70 -0
- data/spec/grape/util/inheritable_values_spec.rb +1 -1
- data/spec/grape/util/stackable_values_spec.rb +1 -1
- data/spec/grape/util/strict_hash_configuration_spec.rb +1 -1
- data/spec/grape/validations/params_scope_spec.rb +64 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +10 -0
- data/spec/grape/validations/validators/coerce_spec.rb +48 -18
- data/spec/grape/validations/validators/default_spec.rb +110 -20
- data/spec/grape/validations/validators/presence_spec.rb +41 -3
- data/spec/grape/validations/validators/regexp_spec.rb +7 -2
- data/spec/grape/validations_spec.rb +20 -1
- data/spec/support/file_streamer.rb +11 -0
- data/spec/support/versioned_helpers.rb +1 -1
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 219bc6e20332454502d7e7955db53424e5828880
|
4
|
+
data.tar.gz: 69cdeb3133100f91ebb0fd32e2ee1e52a130defc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 591cb91662a9b1a5f93889103eca65ed73c2979490d36c01f47f7cfabf926b5988693bfc4502defb394236003669fe60d2cb42b3005778f9be4c2c737975afce
|
7
|
+
data.tar.gz: ca855e03121beca28d6f0888e843c93e118f38acce88870732f9ec5e3073382d76bde1eb831236f64f6fe04fa7681022a4a677553a89abecc3d54a36ae05153a
|
data/.rubocop_todo.yml
CHANGED
@@ -1,63 +1,53 @@
|
|
1
1
|
# This configuration was generated by `rubocop --auto-gen-config`
|
2
|
-
# on
|
2
|
+
# on 2015-06-04 09:15:17 -0400 using RuboCop version 0.31.0.
|
3
3
|
# The point is for the user to remove these configuration records
|
4
4
|
# one by one as the offenses are removed from the code base.
|
5
5
|
# Note that changes in the inspected code, or installation of new
|
6
6
|
# versions of RuboCop, may require this file to be generated again.
|
7
7
|
|
8
|
-
# Offense count:
|
9
|
-
# Cop supports --auto-correct.
|
10
|
-
Lint/UnusedBlockArgument:
|
11
|
-
Enabled: false
|
12
|
-
|
13
|
-
# Offense count: 26
|
14
|
-
# Cop supports --auto-correct.
|
15
|
-
Lint/UnusedMethodArgument:
|
16
|
-
Enabled: false
|
17
|
-
|
18
|
-
# Offense count: 35
|
8
|
+
# Offense count: 37
|
19
9
|
Metrics/AbcSize:
|
20
|
-
Max:
|
10
|
+
Max: 48
|
21
11
|
|
22
|
-
# Offense count:
|
12
|
+
# Offense count: 2
|
23
13
|
Metrics/BlockNesting:
|
24
14
|
Max: 4
|
25
15
|
|
26
16
|
# Offense count: 4
|
27
17
|
# Configuration parameters: CountComments.
|
28
18
|
Metrics/ClassLength:
|
29
|
-
Max:
|
19
|
+
Max: 246
|
30
20
|
|
31
|
-
# Offense count:
|
21
|
+
# Offense count: 23
|
32
22
|
Metrics/CyclomaticComplexity:
|
33
|
-
Max:
|
23
|
+
Max: 20
|
34
24
|
|
35
|
-
# Offense count:
|
25
|
+
# Offense count: 675
|
36
26
|
# Configuration parameters: AllowURI, URISchemes.
|
37
27
|
Metrics/LineLength:
|
38
28
|
Max: 198
|
39
29
|
|
40
|
-
# Offense count:
|
30
|
+
# Offense count: 44
|
41
31
|
# Configuration parameters: CountComments.
|
42
32
|
Metrics/MethodLength:
|
43
33
|
Max: 35
|
44
34
|
|
45
|
-
# Offense count:
|
35
|
+
# Offense count: 8
|
36
|
+
# Configuration parameters: CountComments.
|
37
|
+
Metrics/ModuleLength:
|
38
|
+
Max: 243
|
39
|
+
|
40
|
+
# Offense count: 17
|
46
41
|
Metrics/PerceivedComplexity:
|
47
|
-
Max:
|
42
|
+
Max: 22
|
48
43
|
|
49
44
|
# Offense count: 26
|
50
45
|
# Cop supports --auto-correct.
|
51
|
-
|
46
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods.
|
47
|
+
Style/BlockDelimiters:
|
52
48
|
Enabled: false
|
53
49
|
|
54
|
-
# Offense count:
|
55
|
-
# Cop supports --auto-correct.
|
56
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
57
|
-
Style/ClassCheck:
|
58
|
-
Enabled: false
|
59
|
-
|
60
|
-
# Offense count: 157
|
50
|
+
# Offense count: 174
|
61
51
|
Style/Documentation:
|
62
52
|
Enabled: false
|
63
53
|
|
@@ -69,39 +59,18 @@ Style/DoubleNegation:
|
|
69
59
|
Style/EachWithObject:
|
70
60
|
Enabled: false
|
71
61
|
|
72
|
-
# Offense count:
|
73
|
-
Style/EmptyElse:
|
74
|
-
Enabled: false
|
75
|
-
|
76
|
-
# Offense count: 14
|
62
|
+
# Offense count: 15
|
77
63
|
# Configuration parameters: MinBodyLength.
|
78
64
|
Style/GuardClause:
|
79
65
|
Enabled: false
|
80
66
|
|
81
|
-
# Offense count:
|
82
|
-
# Cop supports --auto-correct.
|
83
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
84
|
-
Style/HashSyntax:
|
85
|
-
Enabled: false
|
86
|
-
|
87
|
-
# Offense count: 15
|
67
|
+
# Offense count: 4
|
88
68
|
# Cop supports --auto-correct.
|
89
|
-
Style/IndentArray:
|
90
|
-
Enabled: false
|
91
|
-
|
92
|
-
# Offense count: 18
|
93
69
|
Style/Lambda:
|
94
70
|
Enabled: false
|
95
71
|
|
96
|
-
# Offense count: 1
|
97
|
-
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
98
|
-
Style/Next:
|
99
|
-
Enabled: false
|
100
|
-
|
101
72
|
# Offense count: 3
|
102
|
-
|
103
|
-
# Configuration parameters: PreferredDelimiters.
|
104
|
-
Style/PercentLiteralDelimiters:
|
73
|
+
Style/MultilineTernaryOperator:
|
105
74
|
Enabled: false
|
106
75
|
|
107
76
|
# Offense count: 3
|
@@ -109,33 +78,7 @@ Style/PercentLiteralDelimiters:
|
|
109
78
|
Style/PredicateName:
|
110
79
|
Enabled: false
|
111
80
|
|
112
|
-
# Offense count:
|
81
|
+
# Offense count: 13
|
113
82
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
114
83
|
Style/RaiseArgs:
|
115
84
|
Enabled: false
|
116
|
-
|
117
|
-
# Offense count: 4
|
118
|
-
# Configuration parameters: MaxSlashes.
|
119
|
-
Style/RegexpLiteral:
|
120
|
-
Enabled: false
|
121
|
-
|
122
|
-
# Offense count: 4
|
123
|
-
# Cop supports --auto-correct.
|
124
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
125
|
-
Style/SpaceBeforeBlockBraces:
|
126
|
-
Enabled: false
|
127
|
-
|
128
|
-
# Offense count: 12
|
129
|
-
# Cop supports --auto-correct.
|
130
|
-
Style/SpaceBeforeSemicolon:
|
131
|
-
Enabled: false
|
132
|
-
|
133
|
-
# Offense count: 1
|
134
|
-
# Cop supports --auto-correct.
|
135
|
-
Style/SpecialGlobalVars:
|
136
|
-
Enabled: false
|
137
|
-
|
138
|
-
# Offense count: 2
|
139
|
-
# Cop supports --auto-correct.
|
140
|
-
Style/UnneededPercentQ:
|
141
|
-
Enabled: false
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
0.12.0 (6/18/2015)
|
2
|
+
==================
|
3
|
+
|
4
|
+
#### Features
|
5
|
+
|
6
|
+
* [#995](https://github.com/intridea/grape/issues/995): Added support for coercion to Set or Set[Other] - [@jordansexton](https://github.com/jordansexton) [@u2](https://github.com/u2).
|
7
|
+
* [#980](https://github.com/intridea/grape/issues/980): Grape is now eager-loaded - [@u2](https://github.com/u2).
|
8
|
+
* [#956](https://github.com/intridea/grape/issues/956): Support `present` with `Grape::Presenters::Presenter` - [@u2](https://github.com/u2).
|
9
|
+
* [#974](https://github.com/intridea/grape/pull/974): Added `error!` to `rescue_from` blocks - [@whatasunnyday](https://github.com/whatasunnyday).
|
10
|
+
* [#950](https://github.com/intridea/grape/pull/950): Status method can now accept one of Rack::Utils status code symbols (:ok, :found, :bad_request, etc.) - [@dabrorius](https://github.com/dabrorius).
|
11
|
+
* [#952](https://github.com/intridea/grape/pull/952): Status method now raises error when called with invalid status code - [@dabrorius](https://github.com/dabrorius).
|
12
|
+
* [#957](https://github.com/intridea/grape/pull/957): Regexp validator now supports `allow_blank`, `nil` value behavior changed - [@calfzhou](https://giihub.com/calfzhou).
|
13
|
+
* [#962](https://github.com/intridea/grape/pull/962): The `default` attribute with `false` value is documented now - [@ajvondrak](https://github.com/ajvondrak).
|
14
|
+
* [#1026](https://github.com/intridea/grape/pull/1026): Added `file` method, explicitly setting a file-like response object - [@dblock](https://github.com/dblock).
|
15
|
+
|
16
|
+
#### Fixes
|
17
|
+
|
18
|
+
* [#994](https://github.com/intridea/grape/pull/994): Fixed optional Array params default to Hash - [@u2](https://github.com/u2).
|
19
|
+
* [#988](https://github.com/intridea/grape/pull/988): Fixed duplicate identical endpoints - [@u2](https://github.com/u2).
|
20
|
+
* [#936](https://github.com/intridea/grape/pull/936): Fixed default params processing for optional groups - [@dm1try](https://github.com/dm1try).
|
21
|
+
* [#942](https://github.com/intridea/grape/pull/942): Fixed forced presence for optional params when based on a reused entity that was also required in another context - [@croeck](https://github.com/croeck).
|
22
|
+
* [#1001](https://github.com/intridea/grape/pull/1001): Fixed calling endpoint with specified format with format in its path - [@hodak](https://github.com/hodak).
|
23
|
+
* [#1005](https://github.com/intridea/grape/pull/1005): Fixed the Grape::Middleware::Globals - [@urkle](https://github.com/urkle).
|
24
|
+
* [#1012](https://github.com/intridea/grape/pull/1012): Fixed `allow_blank: false` with a Boolean value of `false` - [@mfunaro](https://github.com/mfunaro).
|
25
|
+
* [#1023](https://github.com/intridea/grape/issues/1023): Fixes unexpected beahvior with `present` and an object that responds to `merge` but isn't a Hash - [@dblock](https://github.com/dblock).
|
26
|
+
* [#1017](https://github.com/intridea/grape/pull/1017): Fixed `undefined method stringify_keys` with nested mutual exclusive params - [@quickpay](https://github.com/quickpay).
|
27
|
+
|
1
28
|
0.11.0 (2/23/2015)
|
2
29
|
==================
|
3
30
|
|
data/Gemfile
CHANGED
data/Guardfile
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -90,7 +90,8 @@ content negotiation, versioning and much more.
|
|
90
90
|
|
91
91
|
## Stable Release
|
92
92
|
|
93
|
-
You're reading the documentation for the stable release of Grape
|
93
|
+
You're reading the documentation for the stable release of Grape 0.12.0.
|
94
|
+
Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
|
94
95
|
|
95
96
|
## Project Resources
|
96
97
|
|
@@ -272,11 +273,11 @@ Modify `config/routes`:
|
|
272
273
|
mount Twitter::API => '/'
|
273
274
|
```
|
274
275
|
|
275
|
-
Additionally, if the version of your Rails is 4.0+ and the application uses the default model layer of ActiveRecord, you will want to use the
|
276
|
+
Additionally, if the version of your Rails is 4.0+ and the application uses the default model layer of ActiveRecord, you will want to use the [hashie-forbidden_attributes gem](https://github.com/Maxim-Filimonov/hashie-forbidden_attributes). This gem disables the security feature of `strong_params` at the model layer, allowing you the use of Grape's own params validation instead.
|
276
277
|
|
277
278
|
```ruby
|
278
279
|
# Gemfile
|
279
|
-
gem "
|
280
|
+
gem "hashie-forbidden_attributes"
|
280
281
|
```
|
281
282
|
|
282
283
|
See [below](#reloading-api-changes-in-development) for additional code that enables reloading of API changes in development.
|
@@ -314,7 +315,7 @@ version 'v1', using: :path
|
|
314
315
|
|
315
316
|
Using this versioning strategy, clients should pass the desired version in the URL.
|
316
317
|
|
317
|
-
curl
|
318
|
+
curl http://localhost:9292/v1/statuses/public_timeline
|
318
319
|
|
319
320
|
### Header
|
320
321
|
|
@@ -350,6 +351,14 @@ post do
|
|
350
351
|
end
|
351
352
|
```
|
352
353
|
|
354
|
+
You can also use one of status codes symbols that are provided by [Rack utils](http://www.rubydoc.info/github/rack/rack/Rack/Utils#HTTP_STATUS_CODES-constant)
|
355
|
+
|
356
|
+
```ruby
|
357
|
+
post do
|
358
|
+
status :no_content
|
359
|
+
end
|
360
|
+
```
|
361
|
+
|
353
362
|
### Accept-Version Header
|
354
363
|
|
355
364
|
```ruby
|
@@ -374,7 +383,7 @@ version 'v1', using: :param
|
|
374
383
|
Using this versioning strategy, clients should pass the desired version as a request parameter,
|
375
384
|
either in the URL query string or in the request body.
|
376
385
|
|
377
|
-
curl
|
386
|
+
curl http://localhost:9292/statuses/public_timeline?apiver=v1
|
378
387
|
|
379
388
|
The default name for the query parameter is 'apiver' but can be specified using the `:parameter` option.
|
380
389
|
|
@@ -382,7 +391,7 @@ The default name for the query parameter is 'apiver' but can be specified using
|
|
382
391
|
version 'v1', using: :param, parameter: "v"
|
383
392
|
```
|
384
393
|
|
385
|
-
curl
|
394
|
+
curl http://localhost:9292/statuses/public_timeline?v=v1
|
386
395
|
|
387
396
|
|
388
397
|
## Describing Methods
|
@@ -451,7 +460,7 @@ Multipart POSTs and PUTs are supported as well.
|
|
451
460
|
The request:
|
452
461
|
|
453
462
|
```
|
454
|
-
curl --form image_file
|
463
|
+
curl --form image_file='@image.jpg;type=image/jpg' http://localhost:9292/upload
|
455
464
|
```
|
456
465
|
|
457
466
|
The Grape endpoint:
|
@@ -810,7 +819,7 @@ end
|
|
810
819
|
#### `regexp`
|
811
820
|
|
812
821
|
Parameters can be restricted to match a specific regular expression with the `:regexp` option. If the value
|
813
|
-
|
822
|
+
does not match the regular expression an error will be returned. Note that this is true for both `requires`
|
814
823
|
and `optional` parameters.
|
815
824
|
|
816
825
|
```ruby
|
@@ -819,6 +828,13 @@ params do
|
|
819
828
|
end
|
820
829
|
```
|
821
830
|
|
831
|
+
The validator will pass if the parameter was sent without value. To ensure that the parameter contains a value, use `allow_blank: false`.
|
832
|
+
|
833
|
+
```ruby
|
834
|
+
params do
|
835
|
+
requires :email, allow_blank: false, regexp: /.+@.+/
|
836
|
+
end
|
837
|
+
```
|
822
838
|
|
823
839
|
#### `mutually_exclusive`
|
824
840
|
|
@@ -963,7 +979,7 @@ end
|
|
963
979
|
class AlphaNumeric < Grape::Validations::Base
|
964
980
|
def validate_param!(attr_name, params)
|
965
981
|
unless params[attr_name] =~ /^[[:alnum:]]+$/
|
966
|
-
|
982
|
+
fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: "must consist of alpha-numeric characters"
|
967
983
|
end
|
968
984
|
end
|
969
985
|
end
|
@@ -981,7 +997,7 @@ You can also create custom classes that take parameters.
|
|
981
997
|
class Length < Grape::Validations::Base
|
982
998
|
def validate_param!(attr_name, params)
|
983
999
|
unless params[attr_name].length <= @option
|
984
|
-
|
1000
|
+
fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long"
|
985
1001
|
end
|
986
1002
|
end
|
987
1003
|
end
|
@@ -1014,7 +1030,7 @@ You can rescue a `Grape::Exceptions::ValidationErrors` and respond with a custom
|
|
1014
1030
|
```ruby
|
1015
1031
|
format :json
|
1016
1032
|
subject.rescue_from Grape::Exceptions::ValidationErrors do |e|
|
1017
|
-
|
1033
|
+
error! e, 400
|
1018
1034
|
end
|
1019
1035
|
```
|
1020
1036
|
|
@@ -1425,17 +1441,29 @@ class Twitter::API < Grape::API
|
|
1425
1441
|
end
|
1426
1442
|
```
|
1427
1443
|
|
1428
|
-
You can rescue all exceptions with a code block. The `
|
1444
|
+
You can rescue all exceptions with a code block. The `error!` wrapper
|
1429
1445
|
automatically sets the default error code and content-type.
|
1430
1446
|
|
1431
1447
|
```ruby
|
1432
1448
|
class Twitter::API < Grape::API
|
1433
1449
|
rescue_from :all do |e|
|
1434
|
-
|
1450
|
+
error!("rescued from #{e.class.name}")
|
1435
1451
|
end
|
1436
1452
|
end
|
1437
1453
|
```
|
1438
1454
|
|
1455
|
+
Optionally, you can set the format, status code and headers.
|
1456
|
+
|
1457
|
+
```ruby
|
1458
|
+
class Twitter::API < Grape::API
|
1459
|
+
format :json
|
1460
|
+
rescue_from :all do |e|
|
1461
|
+
error!({ error: "Server error.", 500, { 'Content-Type' => 'text/error' } })
|
1462
|
+
end
|
1463
|
+
end
|
1464
|
+
```
|
1465
|
+
|
1466
|
+
|
1439
1467
|
You can also rescue specific exceptions with a code block and handle the Rack
|
1440
1468
|
response at the lowest level.
|
1441
1469
|
|
@@ -1452,10 +1480,11 @@ Or rescue specific exceptions.
|
|
1452
1480
|
```ruby
|
1453
1481
|
class Twitter::API < Grape::API
|
1454
1482
|
rescue_from ArgumentError do |e|
|
1455
|
-
|
1483
|
+
error!("ArgumentError: #{e.message}")
|
1456
1484
|
end
|
1485
|
+
|
1457
1486
|
rescue_from NotImplementedError do |e|
|
1458
|
-
|
1487
|
+
error!("NotImplementedError: #{e.message}")
|
1459
1488
|
end
|
1460
1489
|
end
|
1461
1490
|
```
|
@@ -1475,10 +1504,10 @@ Then the following `rescue_from` clause will rescue exceptions of type `APIError
|
|
1475
1504
|
|
1476
1505
|
```ruby
|
1477
1506
|
rescue_from APIErrors::ParentError do |e|
|
1478
|
-
|
1507
|
+
error!({
|
1479
1508
|
error: "#{e.class} error",
|
1480
1509
|
message: e.message
|
1481
|
-
|
1510
|
+
}, e.status)
|
1482
1511
|
end
|
1483
1512
|
```
|
1484
1513
|
|
@@ -1487,11 +1516,11 @@ The code below will rescue exceptions of type `RuntimeError` but _not_ its subcl
|
|
1487
1516
|
|
1488
1517
|
```ruby
|
1489
1518
|
rescue_from RuntimeError, rescue_subclasses: false do |e|
|
1490
|
-
|
1519
|
+
error!({
|
1491
1520
|
status: e.status,
|
1492
1521
|
message: e.message,
|
1493
1522
|
errors: e.errors
|
1494
|
-
|
1523
|
+
}, e.status)
|
1495
1524
|
end
|
1496
1525
|
```
|
1497
1526
|
|
@@ -1559,6 +1588,8 @@ class API < Grape::API
|
|
1559
1588
|
end
|
1560
1589
|
```
|
1561
1590
|
|
1591
|
+
For similar to Rails request logging try the [grape_logging](https://github.com/aserafin/grape_logging) gem.
|
1592
|
+
|
1562
1593
|
## API Formats
|
1563
1594
|
|
1564
1595
|
Your API can declare which content-types to support by using `content_type`. If you do not specify any, Grape will support
|
@@ -1648,7 +1679,7 @@ end
|
|
1648
1679
|
```
|
1649
1680
|
|
1650
1681
|
You can have your API only respond to a single format with `format`. If you use this, the API will **not** respond to file
|
1651
|
-
extensions
|
1682
|
+
extensions other than specified in `format`. For example, consider the following API.
|
1652
1683
|
|
1653
1684
|
```ruby
|
1654
1685
|
class SingleFormatAPI < Grape::API
|
@@ -1661,7 +1692,8 @@ end
|
|
1661
1692
|
```
|
1662
1693
|
|
1663
1694
|
* `GET /hello` will respond with JSON.
|
1664
|
-
* `GET /hello.
|
1695
|
+
* `GET /hello.json` will respond with JSON.
|
1696
|
+
* `GET /hello.xml`, `GET /hello.foobar`, or *any* other extension will respond with an HTTP 404 error code.
|
1665
1697
|
* `GET /hello?format=xml` will respond with an HTTP 406 error code, because the XML format specified by the request parameter
|
1666
1698
|
is not supported.
|
1667
1699
|
* `GET /hello` with an `Accept: application/xml` header will still respond with JSON, since it could not negotiate a
|
@@ -1922,6 +1954,31 @@ Grape will automatically detect that there is a `Status::Entity` class and use t
|
|
1922
1954
|
representative entity. This can still be overridden by using the `:with` option or an explicit
|
1923
1955
|
`represents` call.
|
1924
1956
|
|
1957
|
+
You can present `hash` with `Grape::Presenters::Presenter` to keep things consistent.
|
1958
|
+
|
1959
|
+
```ruby
|
1960
|
+
get '/users' do
|
1961
|
+
present { id: 10, name: :dgz }, with: Grape::Presenters::Presenter
|
1962
|
+
end
|
1963
|
+
````
|
1964
|
+
The response will be
|
1965
|
+
|
1966
|
+
```ruby
|
1967
|
+
{
|
1968
|
+
id: 10,
|
1969
|
+
name: 'dgz'
|
1970
|
+
}
|
1971
|
+
```
|
1972
|
+
|
1973
|
+
It has the same result with
|
1974
|
+
|
1975
|
+
```ruby
|
1976
|
+
get '/users' do
|
1977
|
+
present :id, 10
|
1978
|
+
present :name, :dgz
|
1979
|
+
end
|
1980
|
+
```
|
1981
|
+
|
1925
1982
|
### Hypermedia and Roar
|
1926
1983
|
|
1927
1984
|
You can use [Roar](https://github.com/apotonick/roar) to render HAL or Collection+JSON with the help of [grape-roar](https://github.com/dblock/grape-roar), which defines a custom JSON formatter and enables presenting entities with Grape's `present` keyword.
|
@@ -1951,7 +2008,7 @@ class API < Grape::API
|
|
1951
2008
|
end
|
1952
2009
|
```
|
1953
2010
|
|
1954
|
-
You can
|
2011
|
+
You can set the response body explicitly with `body`.
|
1955
2012
|
|
1956
2013
|
```ruby
|
1957
2014
|
class API < Grape::API
|
@@ -1965,6 +2022,28 @@ end
|
|
1965
2022
|
|
1966
2023
|
Use `body false` to return `204 No Content` without any data or content-type.
|
1967
2024
|
|
2025
|
+
You can also set the response to a file-like object with `file`.
|
2026
|
+
|
2027
|
+
```ruby
|
2028
|
+
class FileStreamer
|
2029
|
+
def initialize(file_path)
|
2030
|
+
@file_path = file_path
|
2031
|
+
end
|
2032
|
+
|
2033
|
+
def each(&blk)
|
2034
|
+
File.open(@file_path, 'rb') do |file|
|
2035
|
+
file.each(10, &blk)
|
2036
|
+
end
|
2037
|
+
end
|
2038
|
+
end
|
2039
|
+
|
2040
|
+
class API < Grape::API
|
2041
|
+
get '/' do
|
2042
|
+
file FileStreamer.new('file.bin')
|
2043
|
+
end
|
2044
|
+
end
|
2045
|
+
```
|
2046
|
+
|
1968
2047
|
## Authentication
|
1969
2048
|
|
1970
2049
|
### Basic and Digest Auth
|
@@ -2253,14 +2332,14 @@ end
|
|
2253
2332
|
|
2254
2333
|
## Writing Tests
|
2255
2334
|
|
2256
|
-
You can test a Grape API with RSpec by making HTTP requests and examining the response.
|
2257
|
-
|
2258
2335
|
### Writing Tests with Rack
|
2259
2336
|
|
2260
2337
|
Use `rack-test` and define your API as `app`.
|
2261
2338
|
|
2262
2339
|
#### RSpec
|
2263
2340
|
|
2341
|
+
You can test a Grape API with RSpec by making HTTP requests and examining the response.
|
2342
|
+
|
2264
2343
|
```ruby
|
2265
2344
|
require 'spec_helper'
|
2266
2345
|
|
@@ -2290,12 +2369,34 @@ describe Twitter::API do
|
|
2290
2369
|
end
|
2291
2370
|
```
|
2292
2371
|
|
2372
|
+
#### Airborne
|
2373
|
+
|
2374
|
+
You can test with other RSpec-based frameworks, including [Airborne](https://github.com/brooklynDev/airborne), which uses `rack-test` to make requests.
|
2375
|
+
|
2376
|
+
```ruby
|
2377
|
+
require 'airborne'
|
2378
|
+
|
2379
|
+
Airborne.configure do |config|
|
2380
|
+
config.rack_app = Twitter::API
|
2381
|
+
end
|
2382
|
+
|
2383
|
+
describe Twitter::API do
|
2384
|
+
describe "GET /api/statuses/:id" do
|
2385
|
+
it "returns a status by id" do
|
2386
|
+
status = Status.create!
|
2387
|
+
get "/api/statuses/#{status.id}"
|
2388
|
+
expect_json(status.as_json)
|
2389
|
+
end
|
2390
|
+
end
|
2391
|
+
end
|
2392
|
+
```
|
2393
|
+
|
2293
2394
|
#### MiniTest
|
2294
2395
|
|
2295
2396
|
```ruby
|
2296
2397
|
require "test_helper"
|
2297
2398
|
|
2298
|
-
class Twitter::APITest < MiniTest::
|
2399
|
+
class Twitter::APITest < MiniTest::Test
|
2299
2400
|
include Rack::Test::Methods
|
2300
2401
|
|
2301
2402
|
def app
|
@@ -2305,13 +2406,13 @@ class Twitter::APITest < MiniTest::Unit::TestCase
|
|
2305
2406
|
def test_get_api_statuses_public_timeline_returns_an_empty_array_of_statuses
|
2306
2407
|
get "/api/statuses/public_timeline"
|
2307
2408
|
assert last_response.ok?
|
2308
|
-
assert_equal JSON.parse(last_response.body)
|
2409
|
+
assert_equal [], JSON.parse(last_response.body)
|
2309
2410
|
end
|
2310
2411
|
|
2311
2412
|
def test_get_api_statuses_id_returns_a_status_by_id
|
2312
2413
|
status = Status.create!
|
2313
2414
|
get "/api/statuses/#{status.id}"
|
2314
|
-
assert_equal
|
2415
|
+
assert_equal status.to_json, last_response.body
|
2315
2416
|
end
|
2316
2417
|
end
|
2317
2418
|
```
|
@@ -2361,13 +2462,13 @@ class Twitter::APITest < ActiveSupport::TestCase
|
|
2361
2462
|
test "GET /api/statuses/public_timeline returns an empty array of statuses" do
|
2362
2463
|
get "/api/statuses/public_timeline"
|
2363
2464
|
assert last_response.ok?
|
2364
|
-
assert_equal JSON.parse(last_response.body)
|
2465
|
+
assert_equal [], JSON.parse(last_response.body)
|
2365
2466
|
end
|
2366
2467
|
|
2367
2468
|
test "GET /api/statuses/:id returns a status by id" do
|
2368
2469
|
status = Status.create!
|
2369
2470
|
get "/api/statuses/#{status.id}"
|
2370
|
-
assert_equal
|
2471
|
+
assert_equal status.to_json, last_response.body
|
2371
2472
|
end
|
2372
2473
|
end
|
2373
2474
|
```
|
@@ -2457,4 +2558,4 @@ MIT License. See LICENSE for details.
|
|
2457
2558
|
|
2458
2559
|
## Copyright
|
2459
2560
|
|
2460
|
-
Copyright (c) 2010-
|
2561
|
+
Copyright (c) 2010-2015 Michael Bleigh, and Intridea, Inc.
|