grape 0.16.2 → 0.17.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.

Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +4 -0
  3. data/CHANGELOG.md +54 -27
  4. data/Dangerfile +80 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +61 -27
  7. data/README.md +135 -7
  8. data/Rakefile +34 -30
  9. data/UPGRADING.md +21 -0
  10. data/gemfiles/rack_1.5.2.gemfile +21 -0
  11. data/gemfiles/rails_3.gemfile +22 -1
  12. data/gemfiles/rails_4.gemfile +21 -0
  13. data/gemfiles/rails_5.gemfile +34 -0
  14. data/grape.gemspec +0 -14
  15. data/lib/grape.rb +2 -0
  16. data/lib/grape/api.rb +9 -2
  17. data/lib/grape/dsl/headers.rb +1 -1
  18. data/lib/grape/dsl/inside_route.rb +15 -17
  19. data/lib/grape/dsl/middleware.rb +15 -1
  20. data/lib/grape/dsl/parameters.rb +16 -14
  21. data/lib/grape/dsl/request_response.rb +24 -20
  22. data/lib/grape/dsl/routing.rb +11 -10
  23. data/lib/grape/dsl/settings.rb +16 -0
  24. data/lib/grape/endpoint.rb +77 -60
  25. data/lib/grape/exceptions/validation.rb +5 -2
  26. data/lib/grape/exceptions/validation_array_errors.rb +11 -0
  27. data/lib/grape/formatter/xml.rb +1 -1
  28. data/lib/grape/middleware/error.rb +34 -25
  29. data/lib/grape/middleware/formatter.rb +9 -9
  30. data/lib/grape/middleware/stack.rb +110 -0
  31. data/lib/grape/middleware/versioner.rb +1 -1
  32. data/lib/grape/middleware/versioner/accept_version_header.rb +1 -1
  33. data/lib/grape/middleware/versioner/header.rb +3 -3
  34. data/lib/grape/path.rb +10 -2
  35. data/lib/grape/request.rb +1 -1
  36. data/lib/grape/router.rb +10 -19
  37. data/lib/grape/router/pattern.rb +2 -2
  38. data/lib/grape/router/route.rb +3 -3
  39. data/lib/grape/util/content_types.rb +1 -1
  40. data/lib/grape/util/inheritable_setting.rb +7 -2
  41. data/lib/grape/util/reverse_stackable_values.rb +45 -0
  42. data/lib/grape/util/stackable_values.rb +10 -11
  43. data/lib/grape/validations/attributes_iterator.rb +32 -7
  44. data/lib/grape/validations/params_scope.rb +33 -21
  45. data/lib/grape/validations/types.rb +4 -4
  46. data/lib/grape/validations/types/build_coercer.rb +9 -1
  47. data/lib/grape/validations/validators/all_or_none.rb +2 -2
  48. data/lib/grape/validations/validators/allow_blank.rb +10 -11
  49. data/lib/grape/validations/validators/at_least_one_of.rb +1 -1
  50. data/lib/grape/validations/validators/base.rb +16 -6
  51. data/lib/grape/validations/validators/coerce.rb +3 -6
  52. data/lib/grape/validations/validators/default.rb +26 -1
  53. data/lib/grape/validations/validators/exactly_one_of.rb +1 -1
  54. data/lib/grape/validations/validators/mutual_exclusion.rb +1 -1
  55. data/lib/grape/validations/validators/presence.rb +1 -1
  56. data/lib/grape/validations/validators/regexp.rb +1 -1
  57. data/lib/grape/validations/validators/values.rb +1 -1
  58. data/lib/grape/version.rb +1 -1
  59. data/spec/grape/api/custom_validations_spec.rb +3 -3
  60. data/spec/grape/api/parameters_modification_spec.rb +41 -0
  61. data/spec/grape/api_spec.rb +335 -108
  62. data/spec/grape/dsl/logger_spec.rb +1 -1
  63. data/spec/grape/dsl/middleware_spec.rb +25 -5
  64. data/spec/grape/dsl/request_response_spec.rb +20 -6
  65. data/spec/grape/dsl/validations_spec.rb +1 -1
  66. data/spec/grape/endpoint_spec.rb +166 -23
  67. data/spec/grape/entity_spec.rb +0 -2
  68. data/spec/grape/exceptions/body_parse_errors_spec.rb +37 -0
  69. data/spec/grape/exceptions/validation_errors_spec.rb +5 -5
  70. data/spec/grape/exceptions/validation_spec.rb +10 -0
  71. data/spec/grape/integration/global_namespace_function_spec.rb +1 -1
  72. data/spec/grape/integration/rack_spec.rb +1 -1
  73. data/spec/grape/middleware/base_spec.rb +1 -1
  74. data/spec/grape/middleware/exception_spec.rb +2 -2
  75. data/spec/grape/middleware/formatter_spec.rb +4 -4
  76. data/spec/grape/middleware/stack_spec.rb +123 -0
  77. data/spec/grape/middleware/versioner/header_spec.rb +6 -6
  78. data/spec/grape/request_spec.rb +22 -22
  79. data/spec/grape/util/inheritable_setting_spec.rb +23 -0
  80. data/spec/grape/util/reverse_stackable_values_spec.rb +131 -0
  81. data/spec/grape/validations/params_scope_spec.rb +88 -1
  82. data/spec/grape/validations/validators/allow_blank_spec.rb +5 -0
  83. data/spec/grape/validations/validators/coerce_spec.rb +5 -5
  84. data/spec/grape/validations/validators/default_spec.rb +44 -0
  85. data/spec/grape/validations/validators/values_spec.rb +1 -1
  86. data/spec/grape/validations_spec.rb +36 -17
  87. data/spec/spec_helper.rb +1 -8
  88. data/spec/support/versioned_helpers.rb +3 -3
  89. metadata +13 -188
  90. data/gemfiles/rails_3.gemfile.lock +0 -225
  91. data/pkg/grape-0.16.1.gem +0 -0
  92. data/pkg/patch.diff +0 -24
  93. data/tmp/Gemfile.lock +0 -63
data/README.md CHANGED
@@ -95,7 +95,7 @@
95
95
 
96
96
  ## What is Grape?
97
97
 
98
- Grape is a REST-like API micro-framework for Ruby. It's designed to run on Rack
98
+ Grape is a REST-like API framework for Ruby. It's designed to run on Rack
99
99
  or complement existing web application frameworks such as Rails and Sinatra by
100
100
  providing a simple DSL to easily develop RESTful APIs. It has built-in support
101
101
  for common conventions, including multiple formats, subdomain/prefix restriction,
@@ -103,13 +103,14 @@ content negotiation, versioning and much more.
103
103
 
104
104
  ## Stable Release
105
105
 
106
- You're reading the documentation for the stable release of Grape, 0.16.2.
106
+ You're reading the documentation for the stable release of Grape.
107
107
  Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
108
108
 
109
109
  ## Project Resources
110
110
 
111
111
  * [Grape Website](http://www.ruby-grape.org)
112
- * Need help? [Grape Google Group](http://groups.google.com/group/ruby-grape)
112
+ * Need help? Try [Grape Google Group](http://groups.google.com/group/ruby-grape) or [Gitter](https://gitter.im/ruby-grape/grape)
113
+ * [Follow us on Twitter](https://twitter.com/grapeframework)
113
114
 
114
115
  ## Installation
115
116
 
@@ -370,7 +371,8 @@ Using this versioning strategy, clients should pass the desired version in the H
370
371
  By default, the first matching version is used when no `Accept-Version` header is
371
372
  supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
372
373
  one could use the `:strict` option. When this option is set to `true`, a `406 Not Acceptable` error
373
- is returned when no correct `Accept` header is supplied.
374
+ is returned when no correct `Accept` header is supplied and the `:cascade` option is set to `false`.
375
+ Otherwise a `404 Not Found` error is returned by Rack if no other route matches.
374
376
 
375
377
  ### Param
376
378
 
@@ -552,6 +554,52 @@ The returned hash is a `Hashie::Mash` instance, allowing you to access parameter
552
554
  The `#declared` method is not available to `before` filters, as those are evaluated prior
553
555
  to parameter coercion.
554
556
 
557
+ ### Include parent namespaces
558
+
559
+ By default `declared(params)` includes parameters that were defined in all parent namespaces. If you want to return only parameters from your current namespace, you can set `include_parent_namespaces` option to `false`.
560
+
561
+ ````ruby
562
+ format :json
563
+
564
+ namespace :parent do
565
+ params do
566
+ requires :parent_name, type: String
567
+ end
568
+
569
+ namespace ':parent_name' do
570
+ params do
571
+ requires :child_name, type: String
572
+ end
573
+ get ':child_name' do
574
+ {
575
+ 'without_parent_namespaces' => declared(params, include_parent_namespaces: false),
576
+ 'with_parent_namespaces' => declared(params, include_parent_namespaces: true),
577
+ }
578
+ end
579
+ end
580
+ end
581
+ ````
582
+
583
+ **Request**
584
+
585
+ ````bash
586
+ curl -X GET -H "Content-Type: application/json" localhost:9292/parent/foo/bar
587
+ ````
588
+
589
+ **Response**
590
+
591
+ ````json
592
+ {
593
+ "without_parent_namespaces": {
594
+ "child_name": "bar"
595
+ },
596
+ "with_parent_namespaces": {
597
+ "parent_name": "foo",
598
+ "child_name": "bar"
599
+ },
600
+ }
601
+ ````
602
+
555
603
  ### Include missing
556
604
 
557
605
  By default `declared(params)` includes parameters that have `nil` values. If you want to return only the parameters that are not `nil`, you can use the `include_missing` option. By default, `include_missing` is set to `true`. Consider the following API:
@@ -938,6 +986,19 @@ params do
938
986
  end
939
987
  ```
940
988
 
989
+ In the example above Grape will use `blank?` to check whether the `shelf_id` param is present.
990
+
991
+ Given also takes a `Proc` with custom code. Below, the param `description` is required only if the value of `category` is equal `foo`:
992
+
993
+ ```ruby
994
+ params do
995
+ optional :category
996
+ given category: ->(val) { val == 'foo' } do
997
+ requires :description
998
+ end
999
+ end
1000
+ ```
1001
+
941
1002
  ### Built-in Validators
942
1003
 
943
1004
  #### `allow_blank`
@@ -1804,6 +1865,17 @@ class Twitter::API < Grape::API
1804
1865
  end
1805
1866
  ```
1806
1867
 
1868
+ Grape can also rescue from all exceptions and still use the built-in exception handing.
1869
+ This will give the same behavior as `rescue_from :all` with the addition that Grape will use the exception handling defined by all Exception classes that inherit Grape::Exceptions::Base.
1870
+
1871
+ The intent of this setting is to provide a simple way to cover the most common exceptions and return any unexpected exceptions in the API format.
1872
+
1873
+ ```ruby
1874
+ class Twitter::API < Grape::API
1875
+ rescue_from :grape_exceptions
1876
+ end
1877
+ ```
1878
+
1807
1879
  You can also rescue specific exceptions.
1808
1880
 
1809
1881
  ```ruby
@@ -1814,6 +1886,18 @@ end
1814
1886
 
1815
1887
  In this case ```UserDefinedError``` must be inherited from ```StandardError```.
1816
1888
 
1889
+ Notice that you could combine these two approaches (rescuing custom errors takes precedence). For example, it's useful for handling all exceptions except Grape validation errors.
1890
+
1891
+ ```ruby
1892
+ class Twitter::API < Grape::API
1893
+ rescue_from Grape::Exceptions::ValidationErrors do |e|
1894
+ error!(e, 400)
1895
+ end
1896
+
1897
+ rescue_from :all
1898
+ end
1899
+ ```
1900
+
1817
1901
  The error format will match the request format. See "Content-Types" below.
1818
1902
 
1819
1903
  Custom error formatters for existing and additional types can be defined with a proc.
@@ -1861,7 +1945,7 @@ class Twitter::API < Grape::API
1861
1945
  end
1862
1946
  ```
1863
1947
 
1864
- You can also rescue specific exceptions with a code block and handle the Rack response at the lowest level.
1948
+ You can also rescue all exceptions with a code block and handle the Rack response at the lowest level.
1865
1949
 
1866
1950
  ```ruby
1867
1951
  class Twitter::API < Grape::API
@@ -1955,6 +2039,30 @@ class Twitter::API < Grape::API
1955
2039
  end
1956
2040
  ```
1957
2041
 
2042
+ #### Rescuing exceptions inside namespaces
2043
+
2044
+ You could put `rescue_from` clauses inside a namespace and they will take precedence over ones
2045
+ defined in the root scope:
2046
+
2047
+ ```ruby
2048
+ class Twitter::API < Grape::API
2049
+ rescue_from ArgumentError do |e|
2050
+ error!("outer")
2051
+ end
2052
+
2053
+ namespace :statuses do
2054
+ rescue_from ArgumentError do |e|
2055
+ error!("inner")
2056
+ end
2057
+ get do
2058
+ raise ArgumentError.new
2059
+ end
2060
+ end
2061
+ end
2062
+ ```
2063
+
2064
+ Here `'inner'` will be result of handling occured `ArgumentError`.
2065
+
1958
2066
  #### Unrescuable Exceptions
1959
2067
 
1960
2068
  `Grape::Exceptions::InvalidVersionHeader`, which is raised when the version in the request header doesn't match the currently evaluated version for the endpoint, will _never_ be rescued from a `rescue_from` block (even a `rescue_from :all`) This is because Grape relies on Rack to catch that error and try the next versioned-route for cases where there exist identical Grape endpoints with different versions.
@@ -2314,7 +2422,7 @@ module API
2314
2422
  expose :text, documentation: { type: 'string', desc: 'Status update text.' }
2315
2423
  expose :ip, if: { type: :full }
2316
2424
  expose :user_type, :user_id, if: ->(status, options) { status.user.public? }
2317
- expose :digest do |status, options|
2425
+ expose :digest do |status, options|
2318
2426
  Digest::MD5.hexdigest(status.txt)
2319
2427
  end
2320
2428
  expose :replies, using: API::Status, as: :replies
@@ -2805,7 +2913,27 @@ Your middleware can overwrite application response as follows, except error case
2805
2913
  ```ruby
2806
2914
  class Overwriter < Grape::Middleware::Base
2807
2915
  def after
2808
- [200, { 'Content-Type' => 'text/plain' }, ['Overwrited.']]
2916
+ [200, { 'Content-Type' => 'text/plain' }, ['Overwritten.']]
2917
+ end
2918
+ end
2919
+ ```
2920
+
2921
+ You can add your custom middleware with `use`, that push the middleware onto the stack, and you can also control where the middleware is inserted using `insert`, `insert_before` and `insert_after`.
2922
+
2923
+ ```ruby
2924
+ class CustomOverwriter < Grape::Middleware::Base
2925
+ def after
2926
+ [200, { 'Content-Type' => 'text/plain' }, [@options[:message]]]
2927
+ end
2928
+ end
2929
+
2930
+
2931
+ class API < Grape::API
2932
+ use Overwriter
2933
+ insert_before Overwriter, CustomOverwriter, message: 'Overwritten again.'
2934
+ insert 0, CustomOverwriter, message: 'Overwrites all other middleware.'
2935
+
2936
+ get '/' do
2809
2937
  end
2810
2938
  end
2811
2939
  ```
data/Rakefile CHANGED
@@ -23,43 +23,47 @@ RuboCop::RakeTask.new
23
23
 
24
24
  task default: [:rubocop, :spec]
25
25
 
26
- require 'yard'
27
- DOC_FILES = ['lib/**/*.rb', 'README.md']
26
+ begin
27
+ require 'yard'
28
+ DOC_FILES = ['lib/**/*.rb', 'README.md'].freeze
28
29
 
29
- YARD::Rake::YardocTask.new(:doc) do |t|
30
- t.files = DOC_FILES
31
- end
32
-
33
- namespace :doc do
34
- YARD::Rake::YardocTask.new(:pages) do |t|
35
- t.files = DOC_FILES
36
- t.options = ['-o', '../grape.doc/docs']
30
+ YARD::Rake::YardocTask.new(:doc) do |t|
31
+ t.files = DOC_FILES
37
32
  end
38
33
 
39
- namespace :pages do
40
- desc 'Check out gh-pages.'
41
- task :checkout do
42
- dir = File.dirname(__FILE__) + '/../grape.doc'
43
- unless Dir.exist?(dir)
44
- Dir.mkdir(dir)
45
- Dir.chdir(dir) do
46
- system('git init')
47
- system('git remote add origin git@github.com:ruby-grape/grape.git')
48
- system('git pull')
49
- system('git checkout gh-pages')
34
+ namespace :doc do
35
+ YARD::Rake::YardocTask.new(:pages) do |t|
36
+ t.files = DOC_FILES
37
+ t.options = ['-o', '../grape.doc/docs']
38
+ end
39
+
40
+ namespace :pages do
41
+ desc 'Check out gh-pages.'
42
+ task :checkout do
43
+ dir = File.dirname(__FILE__) + '/../grape.doc'
44
+ unless Dir.exist?(dir)
45
+ Dir.mkdir(dir)
46
+ Dir.chdir(dir) do
47
+ system('git init')
48
+ system('git remote add origin git@github.com:ruby-grape/grape.git')
49
+ system('git pull')
50
+ system('git checkout gh-pages')
51
+ end
50
52
  end
51
53
  end
52
- end
53
54
 
54
- desc 'Generate and publish YARD docs to GitHub pages.'
55
- task publish: ['doc:pages:checkout', 'doc:pages'] do
56
- Dir.chdir(File.dirname(__FILE__) + '/../grape.doc') do
57
- system('git checkout gh-pages')
58
- system('git add .')
59
- system('git add -u')
60
- system("git commit -m 'Generating docs for version #{Grape::VERSION}.'")
61
- system('git push origin gh-pages')
55
+ desc 'Generate and publish YARD docs to GitHub pages.'
56
+ task publish: ['doc:pages:checkout', 'doc:pages'] do
57
+ Dir.chdir(File.dirname(__FILE__) + '/../grape.doc') do
58
+ system('git checkout gh-pages')
59
+ system('git add .')
60
+ system('git add -u')
61
+ system("git commit -m 'Generating docs for version #{Grape::VERSION}.'")
62
+ system('git push origin gh-pages')
63
+ end
62
64
  end
63
65
  end
64
66
  end
67
+ rescue LoadError # rubocop:disable Lint/HandleExceptions
68
+ # ignore
65
69
  end
@@ -1,6 +1,27 @@
1
1
  Upgrading Grape
2
2
  ===============
3
3
 
4
+ ### Upgrading to >= 0.17.0
5
+
6
+ #### Removed official support for Ruby < 2.2.2
7
+
8
+ Grape is no longer automatically tested against versions of Ruby prior to 2.2.2. This is because of its dependency on activesupport which, with version 5.0.0, now requires at least Ruby 2.2.2.
9
+
10
+ See [#1441](https://github.com/ruby-grape/grape/pull/1441) for nmore information.
11
+
12
+ #### Changed priority of `rescue_from` clauses applying
13
+
14
+ The `rescue_from` clauses declared inside a namespace would take a priority over ones declared in the root scope.
15
+ This could possibly affect those users who use different `rescue_from` clauses in root scope and in namespaces.
16
+
17
+ See [#1405](https://github.com/ruby-grape/grape/pull/1405) for more inforomation.
18
+
19
+ #### Helper methods injected inside `rescue_from` in middleware
20
+
21
+ Helper methods are injected inside `rescue_from` may cause undesirable effects. For example, definining a helper method called `error!` will take precendence over the built-in `error!` method and should be renamed.
22
+
23
+ See [#1451](https://github.com/ruby-grape/grape/issues/1451) for an example.
24
+
4
25
  ### Upgrading to >= 0.16.0
5
26
 
6
27
  #### Replace rack-mount with new router
@@ -5,9 +5,30 @@ source 'https://rubygems.org'
5
5
  gem 'rack', '1.5.2'
6
6
 
7
7
  group :development, :test do
8
+ gem 'bundler'
9
+ gem 'rake'
10
+ gem 'rubocop', '0.39.0'
11
+ end
12
+
13
+ group :development do
8
14
  gem 'guard'
9
15
  gem 'guard-rspec'
10
16
  gem 'guard-rubocop'
17
+ gem 'yard'
18
+ gem 'appraisal'
19
+ gem 'benchmark-ips'
20
+ gem 'redcarpet'
21
+ end
22
+
23
+ group :test do
24
+ gem 'grape-entity', '0.5.0'
25
+ gem 'maruku'
26
+ gem 'rack-test'
27
+ gem 'rspec', '~> 3.0'
28
+ gem 'cookiejar'
29
+ gem 'rack-jsonp', require: 'rack/jsonp'
30
+ gem 'mime-types', '< 3.0'
31
+ gem 'danger', '~> 2.0'
11
32
  end
12
33
 
13
34
  gemspec path: '../'
@@ -2,13 +2,34 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'rails', '3.2.22'
5
+ gem 'rails', '3.2.19'
6
6
  gem 'rack-cache', '<= 1.2'
7
7
 
8
8
  group :development, :test do
9
+ gem 'bundler'
10
+ gem 'rake'
11
+ gem 'rubocop', '0.39.0'
12
+ end
13
+
14
+ group :development do
9
15
  gem 'guard'
10
16
  gem 'guard-rspec'
11
17
  gem 'guard-rubocop'
18
+ gem 'yard'
19
+ gem 'appraisal'
20
+ gem 'benchmark-ips'
21
+ gem 'redcarpet'
22
+ end
23
+
24
+ group :test do
25
+ gem 'grape-entity', '0.5.0'
26
+ gem 'maruku'
27
+ gem 'rack-test'
28
+ gem 'rspec', '~> 3.0'
29
+ gem 'cookiejar'
30
+ gem 'rack-jsonp', require: 'rack/jsonp'
31
+ gem 'mime-types', '< 3.0'
32
+ gem 'danger', '~> 2.0'
12
33
  end
13
34
 
14
35
  gemspec path: '../'
@@ -5,9 +5,30 @@ source 'https://rubygems.org'
5
5
  gem 'rails', '4.1.6'
6
6
 
7
7
  group :development, :test do
8
+ gem 'bundler'
9
+ gem 'rake'
10
+ gem 'rubocop', '0.39.0'
11
+ end
12
+
13
+ group :development do
8
14
  gem 'guard'
9
15
  gem 'guard-rspec'
10
16
  gem 'guard-rubocop'
17
+ gem 'yard'
18
+ gem 'appraisal'
19
+ gem 'benchmark-ips'
20
+ gem 'redcarpet'
21
+ end
22
+
23
+ group :test do
24
+ gem 'grape-entity', '0.5.0'
25
+ gem 'maruku'
26
+ gem 'rack-test'
27
+ gem 'rspec', '~> 3.0'
28
+ gem 'cookiejar'
29
+ gem 'rack-jsonp', require: 'rack/jsonp'
30
+ gem 'mime-types', '< 3.0'
31
+ gem 'danger', '~> 2.0'
11
32
  end
12
33
 
13
34
  gemspec path: '../'
@@ -0,0 +1,34 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'rails', '5.0.0'
6
+
7
+ group :development, :test do
8
+ gem 'bundler'
9
+ gem 'rake'
10
+ gem 'rubocop', '0.39.0'
11
+ end
12
+
13
+ group :development do
14
+ gem 'guard'
15
+ gem 'guard-rspec'
16
+ gem 'guard-rubocop'
17
+ gem 'yard'
18
+ gem 'appraisal'
19
+ gem 'benchmark-ips'
20
+ gem 'redcarpet'
21
+ end
22
+
23
+ group :test do
24
+ gem 'grape-entity', '0.5.0'
25
+ gem 'maruku'
26
+ gem 'rack-test'
27
+ gem 'rspec', '~> 3.0'
28
+ gem 'cookiejar'
29
+ gem 'rack-jsonp', require: 'rack/jsonp'
30
+ gem 'mime-types', '< 3.0'
31
+ gem 'danger', '~> 2.0'
32
+ end
33
+
34
+ gemspec path: '../'