grape 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of grape might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -66
- data/.rubocop_todo.yml +78 -17
- data/.travis.yml +7 -3
- data/Appraisals +7 -0
- data/CHANGELOG.md +24 -0
- data/CONTRIBUTING.md +7 -0
- data/Gemfile +1 -7
- data/Guardfile +1 -1
- data/README.md +560 -94
- data/RELEASING.md +1 -1
- data/Rakefile +10 -11
- data/UPGRADING.md +211 -3
- data/gemfiles/rails_3.gemfile +14 -0
- data/gemfiles/rails_4.gemfile +14 -0
- data/grape.gemspec +10 -9
- data/lib/backports/active_support/deep_dup.rb +49 -0
- data/lib/backports/active_support/duplicable.rb +88 -0
- data/lib/grape.rb +29 -2
- data/lib/grape/api.rb +59 -65
- data/lib/grape/dsl/api.rb +19 -0
- data/lib/grape/dsl/callbacks.rb +6 -4
- data/lib/grape/dsl/configuration.rb +49 -5
- data/lib/grape/dsl/helpers.rb +7 -8
- data/lib/grape/dsl/inside_route.rb +22 -10
- data/lib/grape/dsl/middleware.rb +5 -5
- data/lib/grape/dsl/parameters.rb +6 -2
- data/lib/grape/dsl/request_response.rb +23 -20
- data/lib/grape/dsl/routing.rb +52 -49
- data/lib/grape/dsl/settings.rb +110 -0
- data/lib/grape/dsl/validations.rb +14 -6
- data/lib/grape/endpoint.rb +104 -88
- data/lib/grape/exceptions/base.rb +2 -2
- data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
- data/lib/grape/exceptions/invalid_formatter.rb +1 -1
- data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -1
- data/lib/grape/exceptions/missing_mime_type.rb +1 -1
- data/lib/grape/exceptions/missing_option.rb +1 -1
- data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
- data/lib/grape/exceptions/unknown_options.rb +1 -1
- data/lib/grape/exceptions/unknown_validator.rb +1 -1
- data/lib/grape/exceptions/validation.rb +1 -1
- data/lib/grape/exceptions/validation_errors.rb +2 -2
- data/lib/grape/formatter/serializable_hash.rb +1 -1
- data/lib/grape/formatter/xml.rb +1 -1
- data/lib/grape/locale/en.yml +2 -0
- data/lib/grape/middleware/auth/dsl.rb +26 -21
- data/lib/grape/middleware/auth/strategies.rb +1 -1
- data/lib/grape/middleware/auth/strategy_info.rb +0 -2
- data/lib/grape/middleware/base.rb +2 -2
- data/lib/grape/middleware/error.rb +1 -1
- data/lib/grape/middleware/formatter.rb +5 -5
- data/lib/grape/middleware/versioner.rb +1 -1
- data/lib/grape/middleware/versioner/header.rb +3 -3
- data/lib/grape/middleware/versioner/param.rb +2 -2
- data/lib/grape/middleware/versioner/path.rb +1 -1
- data/lib/grape/namespace.rb +1 -1
- data/lib/grape/path.rb +9 -3
- data/lib/grape/util/content_types.rb +16 -8
- data/lib/grape/util/inheritable_setting.rb +74 -0
- data/lib/grape/util/inheritable_values.rb +51 -0
- data/lib/grape/util/stackable_values.rb +52 -0
- data/lib/grape/util/strict_hash_configuration.rb +106 -0
- data/lib/grape/validations.rb +0 -220
- data/lib/grape/validations/attributes_iterator.rb +21 -0
- data/lib/grape/validations/params_scope.rb +176 -0
- data/lib/grape/validations/validators/all_or_none.rb +20 -0
- data/lib/grape/validations/validators/allow_blank.rb +30 -0
- data/lib/grape/validations/validators/at_least_one_of.rb +20 -0
- data/lib/grape/validations/validators/base.rb +37 -0
- data/lib/grape/validations/{coerce.rb → validators/coerce.rb} +3 -3
- data/lib/grape/validations/{default.rb → validators/default.rb} +1 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +20 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +26 -0
- data/lib/grape/validations/validators/mutual_exclusion.rb +25 -0
- data/lib/grape/validations/{presence.rb → validators/presence.rb} +2 -2
- data/lib/grape/validations/validators/regexp.rb +12 -0
- data/lib/grape/validations/validators/values.rb +26 -0
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +522 -343
- data/spec/grape/dsl/callbacks_spec.rb +4 -4
- data/spec/grape/dsl/configuration_spec.rb +48 -9
- data/spec/grape/dsl/helpers_spec.rb +6 -13
- data/spec/grape/dsl/inside_route_spec.rb +43 -4
- data/spec/grape/dsl/middleware_spec.rb +1 -10
- data/spec/grape/dsl/parameters_spec.rb +8 -1
- data/spec/grape/dsl/request_response_spec.rb +16 -22
- data/spec/grape/dsl/routing_spec.rb +21 -5
- data/spec/grape/dsl/settings_spec.rb +219 -0
- data/spec/grape/dsl/validations_spec.rb +8 -11
- data/spec/grape/endpoint_spec.rb +115 -86
- data/spec/grape/entity_spec.rb +33 -33
- data/spec/grape/exceptions/invalid_formatter_spec.rb +3 -5
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +4 -6
- data/spec/grape/exceptions/missing_mime_type_spec.rb +5 -6
- data/spec/grape/exceptions/missing_option_spec.rb +3 -5
- data/spec/grape/exceptions/unknown_options_spec.rb +3 -5
- data/spec/grape/exceptions/unknown_validator_spec.rb +3 -5
- data/spec/grape/exceptions/validation_errors_spec.rb +5 -5
- data/spec/grape/loading_spec.rb +44 -0
- data/spec/grape/middleware/auth/base_spec.rb +0 -4
- data/spec/grape/middleware/auth/dsl_spec.rb +2 -4
- data/spec/grape/middleware/auth/strategies_spec.rb +5 -6
- data/spec/grape/middleware/exception_spec.rb +8 -10
- data/spec/grape/middleware/formatter_spec.rb +13 -15
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +10 -10
- data/spec/grape/middleware/versioner/header_spec.rb +25 -25
- data/spec/grape/middleware/versioner/param_spec.rb +15 -17
- data/spec/grape/middleware/versioner/path_spec.rb +1 -2
- data/spec/grape/middleware/versioner_spec.rb +0 -1
- data/spec/grape/path_spec.rb +66 -45
- data/spec/grape/util/inheritable_setting_spec.rb +217 -0
- data/spec/grape/util/inheritable_values_spec.rb +63 -0
- data/spec/grape/util/stackable_values_spec.rb +115 -0
- data/spec/grape/util/strict_hash_configuration_spec.rb +38 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +4 -0
- data/spec/grape/validations/params_scope_spec.rb +57 -0
- data/spec/grape/validations/validators/all_or_none_spec.rb +60 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +170 -0
- data/spec/grape/validations/{at_least_one_of_spec.rb → validators/at_least_one_of_spec.rb} +7 -3
- data/spec/grape/validations/{coerce_spec.rb → validators/coerce_spec.rb} +8 -11
- data/spec/grape/validations/{default_spec.rb → validators/default_spec.rb} +7 -9
- data/spec/grape/validations/{exactly_one_of_spec.rb → validators/exactly_one_of_spec.rb} +15 -11
- data/spec/grape/validations/{mutual_exclusion_spec.rb → validators/mutual_exclusion_spec.rb} +11 -9
- data/spec/grape/validations/{presence_spec.rb → validators/presence_spec.rb} +30 -30
- data/spec/grape/validations/{regexp_spec.rb → validators/regexp_spec.rb} +2 -4
- data/spec/grape/validations/{values_spec.rb → validators/values_spec.rb} +95 -23
- data/spec/grape/validations/{zh-CN.yml → validators/zh-CN.yml} +0 -0
- data/spec/grape/validations_spec.rb +335 -70
- data/spec/shared/versioning_examples.rb +7 -8
- data/spec/spec_helper.rb +2 -0
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- data/spec/support/content_type_helpers.rb +1 -1
- data/spec/support/versioned_helpers.rb +3 -3
- metadata +80 -33
- data/lib/grape/util/deep_merge.rb +0 -23
- data/lib/grape/util/hash_stack.rb +0 -120
- data/lib/grape/validations/at_least_one_of.rb +0 -25
- data/lib/grape/validations/exactly_one_of.rb +0 -26
- data/lib/grape/validations/mutual_exclusion.rb +0 -25
- data/lib/grape/validations/regexp.rb +0 -12
- data/lib/grape/validations/values.rb +0 -23
- data/spec/grape/util/hash_stack_spec.rb +0 -132
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 42e83be7840de205451cdb523c0a03f3a079300f
         | 
| 4 | 
            +
              data.tar.gz: b16053b9a44c001cecae4f670de0073630b7b43e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: cd442f6727d63e80b631e36005c48ac93e639ad3bfd61f102cdcf2530dd67b528c9576e11bad705052108e7448181b74dd32fd4121100009e0bf42451eea6fa9
         | 
| 7 | 
            +
              data.tar.gz: 8f79ccab0811111484bb920ae2b27edbe2c498db8e775fa063b4bf67655f5e6022e561fc22cfd6362e17e1ca27be2e857ef0ed51e8f34b00c4b4bed3e9e06847
         | 
    
        data/.rubocop.yml
    CHANGED
    
    | @@ -2,71 +2,6 @@ AllCops: | |
| 2 2 | 
             
              Exclude:
         | 
| 3 3 | 
             
                - vendor/**/*
         | 
| 4 4 | 
             
                - bin/**/*
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            LineLength:
         | 
| 7 | 
            -
              Enabled: false
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            MethodLength:
         | 
| 10 | 
            -
              Enabled: false
         | 
| 11 | 
            -
             | 
| 12 | 
            -
            ClassLength:
         | 
| 13 | 
            -
              Enabled: false
         | 
| 14 | 
            -
             | 
| 15 | 
            -
            Documentation:
         | 
| 16 | 
            -
              # don't require classes to be documented
         | 
| 17 | 
            -
              Enabled: false
         | 
| 18 | 
            -
             | 
| 19 | 
            -
            CollectionMethods:
         | 
| 20 | 
            -
              # don't prefer map to collect, recuce to inject
         | 
| 21 | 
            -
              Enabled: false
         | 
| 22 | 
            -
             | 
| 23 | 
            -
            Encoding:
         | 
| 24 | 
            -
              # no need to always specify encoding
         | 
| 25 | 
            -
              Enabled: false
         | 
| 26 | 
            -
             | 
| 27 | 
            -
            StringLiterals:
         | 
| 28 | 
            -
              # use single or double-quoted strings, as you please
         | 
| 29 | 
            -
              Enabled: false
         | 
| 30 | 
            -
             | 
| 31 | 
            -
            Void:
         | 
| 32 | 
            -
              # == operator used in void context in specs
         | 
| 33 | 
            -
              Enabled: false
         | 
| 34 | 
            -
             | 
| 35 | 
            -
            SignalException:
         | 
| 36 | 
            -
              # prefer raise to fail
         | 
| 37 | 
            -
              EnforcedStyle: only_raise
         | 
| 38 | 
            -
             | 
| 39 | 
            -
            RaiseArgs:
         | 
| 40 | 
            -
              # don't care for what kind of raise
         | 
| 41 | 
            -
              Enabled: false
         | 
| 42 | 
            -
             | 
| 43 | 
            -
            PerlBackrefs:
         | 
| 44 | 
            -
              # TODO: regular expression matching with $1, $2, etc.
         | 
| 45 | 
            -
              Enabled: false
         | 
| 46 | 
            -
             | 
| 47 | 
            -
            BlockNesting:
         | 
| 48 | 
            -
              # TODO: fix too much nesting
         | 
| 49 | 
            -
              Max: 4
         | 
| 50 | 
            -
             | 
| 51 | 
            -
            Lambda:
         | 
| 52 | 
            -
              # TODO: replace all lambda with -> or Proc
         | 
| 53 | 
            -
              Enabled: false
         | 
| 54 | 
            -
             | 
| 55 | 
            -
            Blocks:
         | 
| 56 | 
            -
              # allow multi-line blocks like expect { }
         | 
| 57 | 
            -
              Enabled: false
         | 
| 58 | 
            -
             | 
| 59 | 
            -
            WordArray:
         | 
| 60 | 
            -
              # %w vs. [ '', ... ]
         | 
| 61 | 
            -
              Enabled: false
         | 
| 62 | 
            -
             | 
| 63 | 
            -
            CyclomaticComplexity:
         | 
| 64 | 
            -
              Enabled: false
         | 
| 65 | 
            -
             | 
| 66 | 
            -
            DoubleNegation:
         | 
| 67 | 
            -
              Enabled: false
         | 
| 68 | 
            -
             | 
| 69 | 
            -
            PredicateName:
         | 
| 70 | 
            -
              Enabled: false
         | 
| 5 | 
            +
                - gemfiles/**/*
         | 
| 71 6 |  | 
| 72 7 | 
             
            inherit_from: .rubocop_todo.yml
         | 
    
        data/.rubocop_todo.yml
    CHANGED
    
    | @@ -1,64 +1,125 @@ | |
| 1 1 | 
             
            # This configuration was generated by `rubocop --auto-gen-config`
         | 
| 2 | 
            -
            # on 2014- | 
| 2 | 
            +
            # on 2014-12-16 11:52:50 -0500 using RuboCop version 0.28.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:  | 
| 8 | 
            +
            # Offense count: 29
         | 
| 9 9 | 
             
            # Cop supports --auto-correct.
         | 
| 10 10 | 
             
            Lint/UnusedBlockArgument:
         | 
| 11 11 | 
             
              Enabled: false
         | 
| 12 12 |  | 
| 13 | 
            -
            # Offense count:  | 
| 13 | 
            +
            # Offense count: 26
         | 
| 14 14 | 
             
            # Cop supports --auto-correct.
         | 
| 15 15 | 
             
            Lint/UnusedMethodArgument:
         | 
| 16 16 | 
             
              Enabled: false
         | 
| 17 17 |  | 
| 18 | 
            -
            # Offense count:  | 
| 18 | 
            +
            # Offense count: 35
         | 
| 19 | 
            +
            Metrics/AbcSize:
         | 
| 20 | 
            +
              Max: 50
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            # Offense count: 1
         | 
| 23 | 
            +
            Metrics/BlockNesting:
         | 
| 24 | 
            +
              Max: 4
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            # Offense count: 4
         | 
| 27 | 
            +
            # Configuration parameters: CountComments.
         | 
| 28 | 
            +
            Metrics/ClassLength:
         | 
| 29 | 
            +
              Max: 243
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            # Offense count: 15
         | 
| 32 | 
            +
            Metrics/CyclomaticComplexity:
         | 
| 33 | 
            +
              Max: 19
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            # Offense count: 545
         | 
| 36 | 
            +
            # Configuration parameters: AllowURI, URISchemes.
         | 
| 37 | 
            +
            Metrics/LineLength:
         | 
| 38 | 
            +
              Max: 198
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            # Offense count: 42
         | 
| 41 | 
            +
            # Configuration parameters: CountComments.
         | 
| 42 | 
            +
            Metrics/MethodLength:
         | 
| 43 | 
            +
              Max: 35
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            # Offense count: 13
         | 
| 46 | 
            +
            Metrics/PerceivedComplexity:
         | 
| 47 | 
            +
              Max: 21
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            # Offense count: 26
         | 
| 50 | 
            +
            # Cop supports --auto-correct.
         | 
| 51 | 
            +
            Style/Blocks:
         | 
| 52 | 
            +
              Enabled: false
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            # Offense count: 6
         | 
| 19 55 | 
             
            # Cop supports --auto-correct.
         | 
| 20 56 | 
             
            # Configuration parameters: EnforcedStyle, SupportedStyles.
         | 
| 21 57 | 
             
            Style/ClassCheck:
         | 
| 22 58 | 
             
              Enabled: false
         | 
| 23 59 |  | 
| 24 | 
            -
            # Offense count:  | 
| 60 | 
            +
            # Offense count: 157
         | 
| 61 | 
            +
            Style/Documentation:
         | 
| 62 | 
            +
              Enabled: false
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            # Offense count: 7
         | 
| 65 | 
            +
            Style/DoubleNegation:
         | 
| 66 | 
            +
              Enabled: false
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            # Offense count: 5
         | 
| 25 69 | 
             
            Style/EachWithObject:
         | 
| 26 70 | 
             
              Enabled: false
         | 
| 27 71 |  | 
| 28 | 
            -
            # Offense count:  | 
| 72 | 
            +
            # Offense count: 1
         | 
| 73 | 
            +
            Style/EmptyElse:
         | 
| 74 | 
            +
              Enabled: false
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            # Offense count: 14
         | 
| 29 77 | 
             
            # Configuration parameters: MinBodyLength.
         | 
| 30 78 | 
             
            Style/GuardClause:
         | 
| 31 79 | 
             
              Enabled: false
         | 
| 32 80 |  | 
| 33 | 
            -
            # Offense count:  | 
| 81 | 
            +
            # Offense count: 3
         | 
| 34 82 | 
             
            # Cop supports --auto-correct.
         | 
| 35 83 | 
             
            # Configuration parameters: EnforcedStyle, SupportedStyles.
         | 
| 36 84 | 
             
            Style/HashSyntax:
         | 
| 37 85 | 
             
              Enabled: false
         | 
| 38 86 |  | 
| 39 | 
            -
            # Offense count:  | 
| 87 | 
            +
            # Offense count: 15
         | 
| 40 88 | 
             
            # Cop supports --auto-correct.
         | 
| 41 89 | 
             
            Style/IndentArray:
         | 
| 42 90 | 
             
              Enabled: false
         | 
| 43 91 |  | 
| 44 | 
            -
            # Offense count:  | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
            Style/IndentHash:
         | 
| 48 | 
            -
              Enabled: true
         | 
| 92 | 
            +
            # Offense count: 18
         | 
| 93 | 
            +
            Style/Lambda:
         | 
| 94 | 
            +
              Enabled: false
         | 
| 49 95 |  | 
| 50 | 
            -
            # Offense count:  | 
| 51 | 
            -
            # Configuration parameters: EnforcedStyle, SupportedStyles.
         | 
| 96 | 
            +
            # Offense count: 1
         | 
| 97 | 
            +
            # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
         | 
| 52 98 | 
             
            Style/Next:
         | 
| 53 99 | 
             
              Enabled: false
         | 
| 54 100 |  | 
| 55 | 
            -
            # Offense count:  | 
| 101 | 
            +
            # Offense count: 3
         | 
| 56 102 | 
             
            # Cop supports --auto-correct.
         | 
| 57 103 | 
             
            # Configuration parameters: PreferredDelimiters.
         | 
| 58 104 | 
             
            Style/PercentLiteralDelimiters:
         | 
| 59 105 | 
             
              Enabled: false
         | 
| 60 106 |  | 
| 61 | 
            -
            # Offense count:  | 
| 107 | 
            +
            # Offense count: 3
         | 
| 108 | 
            +
            # Configuration parameters: NamePrefix, NamePrefixBlacklist.
         | 
| 109 | 
            +
            Style/PredicateName:
         | 
| 110 | 
            +
              Enabled: false
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            # Offense count: 9
         | 
| 113 | 
            +
            # Configuration parameters: EnforcedStyle, SupportedStyles.
         | 
| 114 | 
            +
            Style/RaiseArgs:
         | 
| 115 | 
            +
              Enabled: false
         | 
| 116 | 
            +
             | 
| 117 | 
            +
            # Offense count: 4
         | 
| 118 | 
            +
            # Configuration parameters: MaxSlashes.
         | 
| 119 | 
            +
            Style/RegexpLiteral:
         | 
| 120 | 
            +
              Enabled: false
         | 
| 121 | 
            +
             | 
| 122 | 
            +
            # Offense count: 4
         | 
| 62 123 | 
             
            # Cop supports --auto-correct.
         | 
| 63 124 | 
             
            # Configuration parameters: EnforcedStyle, SupportedStyles.
         | 
| 64 125 | 
             
            Style/SpaceBeforeBlockBraces:
         | 
    
        data/.travis.yml
    CHANGED
    
    | @@ -1,10 +1,9 @@ | |
| 1 1 | 
             
            language: ruby
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            sudo: false
         | 
| 4 4 |  | 
| 5 5 | 
             
            rvm:
         | 
| 6 | 
            -
              - 2.1 | 
| 7 | 
            -
              - 2.1.0
         | 
| 6 | 
            +
              - 2.1
         | 
| 8 7 | 
             
              - 2.0.0
         | 
| 9 8 | 
             
              - 1.9.3
         | 
| 10 9 | 
             
              - rbx-2.2.10
         | 
| @@ -16,3 +15,8 @@ matrix: | |
| 16 15 | 
             
              allow_failures:
         | 
| 17 16 | 
             
                - rvm: ruby-head
         | 
| 18 17 | 
             
                - rvm: jruby-head
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            gemfile:
         | 
| 20 | 
            +
              - Gemfile
         | 
| 21 | 
            +
              - gemfiles/rails_3.gemfile
         | 
| 22 | 
            +
              - gemfiles/rails_4.gemfile
         | 
    
        data/Appraisals
    ADDED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,27 @@ | |
| 1 | 
            +
            0.10.0 (12/19/2014)
         | 
| 2 | 
            +
            ===================
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            * [#803](https://github.com/intridea/grape/pull/803), [#820](https://github.com/intridea/grape/pull/820): Added `all_or_none_of` parameter validator - [@loveltyoic](https://github.com/loveltyoic), [@natecj](https://github.com/natecj).
         | 
| 5 | 
            +
            * [#774](https://github.com/intridea/grape/pull/774): Extended `mutually_exclusive`, `exactly_one_of`, `at_least_one_of` to work inside any kind of group: `requires` or `optional`, `Hash` or `Array` - [@ShPakvel](https://github.com/ShPakvel).
         | 
| 6 | 
            +
            * [#743](https://github.com/intridea/grape/pull/743): Added `allow_blank` parameter validator to validate non-empty strings - [@elado](https://github.com/elado).
         | 
| 7 | 
            +
            * [#745](https://github.com/intridea/grape/pull/745): Removed `atom+xml`, `rss+xml`, and `jsonapi` content-types - [@akabraham](https://github.com/akabraham).
         | 
| 8 | 
            +
            * [#745](https://github.com/intridea/grape/pull/745): Added `:binary, application/octet-stream` content-type - [@akabraham](https://github.com/akabraham).
         | 
| 9 | 
            +
            * [#757](https://github.com/intridea/grape/pull/757): Changed `desc` can now be used with a block syntax - [@dspaeth-faber](https://github.com/dspaeth-faber).
         | 
| 10 | 
            +
            * [#779](https://github.com/intridea/grape/pull/779): Fixed using `values` with a `default` proc - [@ShPakvel](https://github.com/ShPakvel).
         | 
| 11 | 
            +
            * [#799](https://github.com/intridea/grape/pull/799): Fixed custom validators with required `Hash`, `Array` types - [@bwalex](https://github.com/bwalex).
         | 
| 12 | 
            +
            * [#784](https://github.com/intridea/grape/pull/784): Fixed `present` to not overwrite the previously added contents of the response body whebn called more than once - [@mfunaro](https://github.com/mfunaro).
         | 
| 13 | 
            +
            * [#809](https://github.com/intridea/grape/pull/809): Removed automatic `(.:format)` suffix on paths if you're using only one format (e.g., with `format :json`, `/path` will respond with JSON but `/path.xml` will be a 404) - [@ajvondrak](https://github.com/ajvondrak).
         | 
| 14 | 
            +
            * [#816](https://github.com/intridea/grape/pull/816): Added ability to filter out missing params if params is a nested hash with `declared(params, include_missing: false)` - [@georgimitev](https://github.com/georgimitev).
         | 
| 15 | 
            +
            * [#819](https://github.com/intridea/grape/pull/819): Allowed both `desc` and `description` in the params DSL - [@mzikherman](https://github.com/mzikherman).
         | 
| 16 | 
            +
            * [#821](https://github.com/intridea/grape/pull/821): Fixed passing string value when hash is expected in params - [@rebelact](https://github.com/rebelact).
         | 
| 17 | 
            +
            * [#824](https://github.com/intridea/grape/pull/824): Validate array params against list of acceptable values - [@dnd](https://github.com/dnd).
         | 
| 18 | 
            +
            * [#813](https://github.com/intridea/grape/pull/813): Routing methods dsl refactored to get rid of explicit `paths` parameter - [@AlexYankee](https://github.com/AlexYankee).
         | 
| 19 | 
            +
            * [#826](https://github.com/intridea/grape/pull/826): Find `coerce_type` for `Array` when not specified - [@manovotn](https://github.com/manovotn).
         | 
| 20 | 
            +
            * [#645](https://github.com/intridea/grape/issues/645): Invoking `body false` will return `204 No Content` - [@dblock](https://github.com/dblock).
         | 
| 21 | 
            +
            * [#801](https://github.com/intridea/grape/issues/801): Only evaluate permitted parameter `values` and `default` lazily on each request when declared as a proc - [@dblock](https://github.com/dblock).
         | 
| 22 | 
            +
            * [#679](https://github.com/intridea/grape/issues/679): Fixed `OPTIONS` method returning 404 when combined with `prefix`- [@dblock](https://github.com/dblock).
         | 
| 23 | 
            +
            * [#679](https://github.com/intridea/grape/issues/679): Fixed unsupported methods returning 404 instead of 405 when combined with `prefix`- [@dblock](https://github.com/dblock).
         | 
| 24 | 
            +
             | 
| 1 25 | 
             
            0.9.0 (8/27/2014)
         | 
| 2 26 | 
             
            =================
         | 
| 3 27 |  | 
    
        data/CONTRIBUTING.md
    CHANGED
    
    | @@ -32,6 +32,13 @@ bundle install | |
| 32 32 | 
             
            bundle exec rake
         | 
| 33 33 | 
             
            ```
         | 
| 34 34 |  | 
| 35 | 
            +
            Run tests against all supported versions of Rails.
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            ```
         | 
| 38 | 
            +
            appraisal install
         | 
| 39 | 
            +
            appraisal rake spec
         | 
| 40 | 
            +
            ```
         | 
| 41 | 
            +
             | 
| 35 42 | 
             
            #### Write Tests
         | 
| 36 43 |  | 
| 37 44 | 
             
            Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [spec/grape](spec/grape).
         | 
    
        data/Gemfile
    CHANGED
    
    | @@ -3,14 +3,8 @@ source 'http://rubygems.org' | |
| 3 3 | 
             
            gemspec
         | 
| 4 4 |  | 
| 5 5 | 
             
            group :development, :test do
         | 
| 6 | 
            -
              gem 'rubocop', '~> 0. | 
| 6 | 
            +
              gem 'rubocop', '~> 0.28.0'
         | 
| 7 7 | 
             
              gem 'guard'
         | 
| 8 8 | 
             
              gem 'guard-rspec'
         | 
| 9 9 | 
             
              gem 'guard-rubocop'
         | 
| 10 10 | 
             
            end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
            platforms :rbx do
         | 
| 13 | 
            -
              gem 'rubysl'
         | 
| 14 | 
            -
              gem 'rubinius-developer_tools'
         | 
| 15 | 
            -
              gem 'racc'
         | 
| 16 | 
            -
            end
         | 
    
        data/Guardfile
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -11,6 +11,7 @@ | |
| 11 11 | 
             
            - [Basic Usage](#basic-usage)
         | 
| 12 12 | 
             
            - [Mounting](#mounting)
         | 
| 13 13 | 
             
              - [Rack](#rack)
         | 
| 14 | 
            +
              - [ActiveRecord without Rails](#activerecord-without-rails)
         | 
| 14 15 | 
             
              - [Alongside Sinatra (or other frameworks)](#alongside-sinatra-or-other-frameworks)
         | 
| 15 16 | 
             
              - [Rails](#rails)
         | 
| 16 17 | 
             
              - [Modules](#modules)
         | 
| @@ -21,7 +22,10 @@ | |
| 21 22 | 
             
              - [Param](#param)
         | 
| 22 23 | 
             
            - [Describing Methods](#describing-methods)
         | 
| 23 24 | 
             
            - [Parameters](#parameters)
         | 
| 25 | 
            +
              - [Declared](#declared)
         | 
| 26 | 
            +
              - [Include Missing](#include-missing)
         | 
| 24 27 | 
             
            - [Parameter Validation and Coercion](#parameter-validation-and-coercion)
         | 
| 28 | 
            +
              - [Built-in Validators](#built-in-validators)
         | 
| 25 29 | 
             
              - [Namespace Validation and Coercion](#namespace-validation-and-coercion)
         | 
| 26 30 | 
             
              - [Custom Validators](#custom-validators)
         | 
| 27 31 | 
             
              - [Validation Errors](#validation-errors)
         | 
| @@ -50,17 +54,22 @@ | |
| 50 54 | 
             
              - [Hypermedia](#hypermedia)
         | 
| 51 55 | 
             
              - [Rabl](#rabl)
         | 
| 52 56 | 
             
              - [Active Model Serializers](#active-model-serializers)
         | 
| 57 | 
            +
            - [Sending Raw or No Data](#sending-raw-or-no-data)
         | 
| 53 58 | 
             
            - [Authentication](#authentication)
         | 
| 54 59 | 
             
            - [Describing and Inspecting an API](#describing-and-inspecting-an-api)
         | 
| 55 60 | 
             
            - [Current Route and Endpoint](#current-route-and-endpoint)
         | 
| 56 61 | 
             
            - [Before and After](#before-and-after)
         | 
| 57 62 | 
             
            - [Anchoring](#anchoring)
         | 
| 63 | 
            +
            - [Using Custom Middleware](#using-custom-middleware)
         | 
| 64 | 
            +
              - [Rails Middleware](#rails-middleware)
         | 
| 65 | 
            +
                - [Remote IP](#remote-ip)
         | 
| 58 66 | 
             
            - [Writing Tests](#writing-tests)
         | 
| 59 67 | 
             
              - [Writing Tests with Rack](#writing-tests-with-rack)
         | 
| 60 68 | 
             
              - [Writing Tests with Rails](#writing-tests-with-rails)
         | 
| 61 69 | 
             
              - [Stubbing Helpers](#stubbing-helpers)
         | 
| 62 70 | 
             
            - [Reloading API Changes in Development](#reloading-api-changes-in-development)
         | 
| 63 | 
            -
              - [ | 
| 71 | 
            +
              - [Reloading in Rack Applications](#reloading-in-rack-applications)
         | 
| 72 | 
            +
              - [Reloading in Rails Applications](#reloading-in-rails-applications)
         | 
| 64 73 | 
             
            - [Performance Monitoring](#performance-monitoring)
         | 
| 65 74 | 
             
            - [Contributing to Grape](#contributing-to-grape)
         | 
| 66 75 | 
             
            - [Hacking on Grape](#hacking-on-grape)
         | 
| @@ -77,7 +86,8 @@ content negotiation, versioning and much more. | |
| 77 86 |  | 
| 78 87 | 
             
            ## Stable Release
         | 
| 79 88 |  | 
| 80 | 
            -
            You're reading the documentation for Grape  | 
| 89 | 
            +
            You're reading the documentation for the stable release of Grape, 0.10.0.
         | 
| 90 | 
            +
            Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
         | 
| 81 91 |  | 
| 82 92 | 
             
            ## Project Resources
         | 
| 83 93 |  | 
| @@ -107,6 +117,7 @@ module Twitter | |
| 107 117 | 
             
              class API < Grape::API
         | 
| 108 118 | 
             
                version 'v1', using: :header, vendor: 'twitter'
         | 
| 109 119 | 
             
                format :json
         | 
| 120 | 
            +
                prefix :api
         | 
| 110 121 |  | 
| 111 122 | 
             
                helpers do
         | 
| 112 123 | 
             
                  def current_user
         | 
| @@ -191,15 +202,29 @@ run Twitter::API | |
| 191 202 |  | 
| 192 203 | 
             
            And would respond to the following routes:
         | 
| 193 204 |  | 
| 194 | 
            -
                GET /statuses/public_timeline | 
| 195 | 
            -
                GET /statuses/home_timeline | 
| 196 | 
            -
                GET /statuses/:id | 
| 197 | 
            -
                POST /statuses | 
| 198 | 
            -
                PUT /statuses/:id | 
| 199 | 
            -
                DELETE /statuses/:id | 
| 205 | 
            +
                GET /api/statuses/public_timeline
         | 
| 206 | 
            +
                GET /api/statuses/home_timeline
         | 
| 207 | 
            +
                GET /api/statuses/:id
         | 
| 208 | 
            +
                POST /api/statuses
         | 
| 209 | 
            +
                PUT /api/statuses/:id
         | 
| 210 | 
            +
                DELETE /api/statuses/:id
         | 
| 200 211 |  | 
| 201 212 | 
             
            Grape will also automatically respond to HEAD and OPTIONS for all GET, and just OPTIONS for all other routes.
         | 
| 202 213 |  | 
| 214 | 
            +
            ### ActiveRecord without Rails
         | 
| 215 | 
            +
             | 
| 216 | 
            +
            If you want to use ActiveRecord within Grape, you will need to make sure that ActiveRecord's connection pool
         | 
| 217 | 
            +
            is handled correctly.
         | 
| 218 | 
            +
             | 
| 219 | 
            +
            The easiest way to achieve that is by using ActiveRecord's `ConnectionManagement` middleware in your
         | 
| 220 | 
            +
            `config.ru` before mounting Grape, e.g.:
         | 
| 221 | 
            +
             | 
| 222 | 
            +
            ```ruby
         | 
| 223 | 
            +
            use ActiveRecord::ConnectionAdapters::ConnectionManagement
         | 
| 224 | 
            +
             | 
| 225 | 
            +
            run Twitter::API
         | 
| 226 | 
            +
            ```
         | 
| 227 | 
            +
             | 
| 203 228 | 
             
            ### Alongside Sinatra (or other frameworks)
         | 
| 204 229 |  | 
| 205 230 | 
             
            If you wish to mount Grape alongside another Rack framework such as Sinatra, you can do so easily using
         | 
| @@ -244,6 +269,13 @@ Modify `config/routes`: | |
| 244 269 | 
             
            mount Twitter::API => '/'
         | 
| 245 270 | 
             
            ```
         | 
| 246 271 |  | 
| 272 | 
            +
            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_rails` [gem](http://rubygems.org/gems/hashie_rails). This gem disables the security feature of `strong_params` at the model layer, allowing you the use of Grape's own params validation instead.
         | 
| 273 | 
            +
             | 
| 274 | 
            +
            ```ruby
         | 
| 275 | 
            +
            # Gemfile
         | 
| 276 | 
            +
            gem "hashie_rails"
         | 
| 277 | 
            +
            ```
         | 
| 278 | 
            +
             | 
| 247 279 | 
             
            See below for additional code that enables reloading of API changes in development.
         | 
| 248 280 |  | 
| 249 281 | 
             
            ### Modules
         | 
| @@ -355,12 +387,34 @@ version 'v1', using: :param, parameter: "v" | |
| 355 387 | 
             
            You can add a description to API methods and namespaces.
         | 
| 356 388 |  | 
| 357 389 | 
             
            ```ruby
         | 
| 358 | 
            -
            desc "Returns your public timeline."
         | 
| 390 | 
            +
            desc "Returns your public timeline." do
         | 
| 391 | 
            +
              detail 'more details'
         | 
| 392 | 
            +
              params  API::Entities::Status.documentation
         | 
| 393 | 
            +
              success API::Entities::Entity
         | 
| 394 | 
            +
              failure [[401, 'Unauthorized', "Entities::Error"]]
         | 
| 395 | 
            +
              named 'My named route'
         | 
| 396 | 
            +
              headers [XAuthToken: {
         | 
| 397 | 
            +
                         description: 'Valdates your identity',
         | 
| 398 | 
            +
                         required: true
         | 
| 399 | 
            +
                       },
         | 
| 400 | 
            +
                       XOptionalHeader: {
         | 
| 401 | 
            +
                         description: 'Not really needed',
         | 
| 402 | 
            +
                        required: false
         | 
| 403 | 
            +
                       }
         | 
| 404 | 
            +
                      ]
         | 
| 405 | 
            +
            end
         | 
| 359 406 | 
             
            get :public_timeline do
         | 
| 360 407 | 
             
              Status.limit(20)
         | 
| 361 408 | 
             
            end
         | 
| 362 409 | 
             
            ```
         | 
| 363 410 |  | 
| 411 | 
            +
            * `detail`: A more enhanced description
         | 
| 412 | 
            +
            * `params`: Define parameters directly from an `Entity`
         | 
| 413 | 
            +
            * `success`: (former entity) The `Entity` to be used to present by default this route
         | 
| 414 | 
            +
            * `failure`: (former http_codes) A definition of the used failure HTTP Codes and Entities
         | 
| 415 | 
            +
            * `named`: A helper to give a route a name and find it with this name in the documentation Hash
         | 
| 416 | 
            +
            * `headers`: A definition of the used Headers
         | 
| 417 | 
            +
             | 
| 364 418 | 
             
            ## Parameters
         | 
| 365 419 |  | 
| 366 420 | 
             
            Request parameters are available through the `params` hash object. This includes `GET`, `POST`
         | 
| @@ -413,6 +467,176 @@ In the case of conflict between either of: | |
| 413 467 |  | 
| 414 468 | 
             
            route string parameters will have precedence.
         | 
| 415 469 |  | 
| 470 | 
            +
            #### Declared
         | 
| 471 | 
            +
             | 
| 472 | 
            +
            Grape allows you to access only the parameters that have been declared by your `params` block. It filters out the params that have been passed, but are not allowed. Let's have the following api:
         | 
| 473 | 
            +
             | 
| 474 | 
            +
            ````ruby
         | 
| 475 | 
            +
            format :json
         | 
| 476 | 
            +
             | 
| 477 | 
            +
            post 'users/signup' do
         | 
| 478 | 
            +
              { "declared_params" => declared(params) }
         | 
| 479 | 
            +
            end
         | 
| 480 | 
            +
            ````
         | 
| 481 | 
            +
             | 
| 482 | 
            +
            If we do not specify any params, declared will return an empty hash.
         | 
| 483 | 
            +
             | 
| 484 | 
            +
            **Request**
         | 
| 485 | 
            +
             | 
| 486 | 
            +
            ````bash
         | 
| 487 | 
            +
            curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d '{"user": {"first_name":"first name", "last_name": "last name"}}'
         | 
| 488 | 
            +
            ````
         | 
| 489 | 
            +
             | 
| 490 | 
            +
            **Response**
         | 
| 491 | 
            +
             | 
| 492 | 
            +
            ````json
         | 
| 493 | 
            +
            {
         | 
| 494 | 
            +
              "declared_params": {}
         | 
| 495 | 
            +
            }
         | 
| 496 | 
            +
             | 
| 497 | 
            +
            ````
         | 
| 498 | 
            +
             | 
| 499 | 
            +
            Once we add parameters requirements, grape will start returning only the declared params.
         | 
| 500 | 
            +
             | 
| 501 | 
            +
            ````ruby
         | 
| 502 | 
            +
            format :json
         | 
| 503 | 
            +
             | 
| 504 | 
            +
            params do
         | 
| 505 | 
            +
              requires :user, type: Hash do
         | 
| 506 | 
            +
                requires :first_name, type: String
         | 
| 507 | 
            +
                requires :last_name, type: String
         | 
| 508 | 
            +
              end
         | 
| 509 | 
            +
            end
         | 
| 510 | 
            +
             | 
| 511 | 
            +
            post 'users/signup' do
         | 
| 512 | 
            +
              { "declared_params" => declared(params) }
         | 
| 513 | 
            +
            end
         | 
| 514 | 
            +
            ````
         | 
| 515 | 
            +
             | 
| 516 | 
            +
            **Request**
         | 
| 517 | 
            +
             | 
| 518 | 
            +
            ````bash
         | 
| 519 | 
            +
            curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d '{"user": {"first_name":"first name", "last_name": "last name", "random": "never shown"}}'
         | 
| 520 | 
            +
            ````
         | 
| 521 | 
            +
             | 
| 522 | 
            +
            **Response**
         | 
| 523 | 
            +
             | 
| 524 | 
            +
            ````json
         | 
| 525 | 
            +
            {
         | 
| 526 | 
            +
              "declared_params": {
         | 
| 527 | 
            +
                "user": {
         | 
| 528 | 
            +
                  "first_name": "first name",
         | 
| 529 | 
            +
                  "last_name": "last name"
         | 
| 530 | 
            +
                }
         | 
| 531 | 
            +
              }
         | 
| 532 | 
            +
            }
         | 
| 533 | 
            +
            ````
         | 
| 534 | 
            +
             | 
| 535 | 
            +
            #### Include missing
         | 
| 536 | 
            +
             | 
| 537 | 
            +
            By default `declared(params)` returns parameters that has `nil` value. If you want to return only the parameters that have any value, you can use the `include_missing` option. By default it is `true`. Let's have the following api:
         | 
| 538 | 
            +
             | 
| 539 | 
            +
            ````ruby
         | 
| 540 | 
            +
            format :json
         | 
| 541 | 
            +
             | 
| 542 | 
            +
            params do
         | 
| 543 | 
            +
              requires :first_name, type: String
         | 
| 544 | 
            +
              optional :last_name, type: String
         | 
| 545 | 
            +
            end
         | 
| 546 | 
            +
             | 
| 547 | 
            +
            post 'users/signup' do
         | 
| 548 | 
            +
              { "declared_params" => declared(params, include_missing: false) }
         | 
| 549 | 
            +
            end
         | 
| 550 | 
            +
            ````
         | 
| 551 | 
            +
             | 
| 552 | 
            +
            **Request**
         | 
| 553 | 
            +
             | 
| 554 | 
            +
            ````bash
         | 
| 555 | 
            +
            curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d '{"user": {"first_name":"first name", "random": "never shown"}}'
         | 
| 556 | 
            +
            ````
         | 
| 557 | 
            +
             | 
| 558 | 
            +
            **Response with include_missing:false**
         | 
| 559 | 
            +
             | 
| 560 | 
            +
            ````json
         | 
| 561 | 
            +
            {
         | 
| 562 | 
            +
              "declared_params": {
         | 
| 563 | 
            +
                "user": {
         | 
| 564 | 
            +
                  "first_name": "first name"
         | 
| 565 | 
            +
                }
         | 
| 566 | 
            +
              }
         | 
| 567 | 
            +
            }
         | 
| 568 | 
            +
            ````
         | 
| 569 | 
            +
             | 
| 570 | 
            +
            **Response with include_missing:true**
         | 
| 571 | 
            +
             | 
| 572 | 
            +
            ````json
         | 
| 573 | 
            +
            {
         | 
| 574 | 
            +
              "declared_params": {
         | 
| 575 | 
            +
                "first_name": "first name",
         | 
| 576 | 
            +
                "last_name": null
         | 
| 577 | 
            +
              }
         | 
| 578 | 
            +
            }
         | 
| 579 | 
            +
            ````
         | 
| 580 | 
            +
             | 
| 581 | 
            +
            It also works on nested hashes:
         | 
| 582 | 
            +
             | 
| 583 | 
            +
            ````ruby
         | 
| 584 | 
            +
            format :json
         | 
| 585 | 
            +
             | 
| 586 | 
            +
            params do
         | 
| 587 | 
            +
              requires :user, :type => Hash do
         | 
| 588 | 
            +
                requires :first_name, type: String
         | 
| 589 | 
            +
                optional :last_name, type: String
         | 
| 590 | 
            +
                requires :address, :type => Hash do
         | 
| 591 | 
            +
                  requires :city, type: String
         | 
| 592 | 
            +
                  optional :region, type: String
         | 
| 593 | 
            +
                end
         | 
| 594 | 
            +
              end
         | 
| 595 | 
            +
            end
         | 
| 596 | 
            +
             | 
| 597 | 
            +
            post 'users/signup' do
         | 
| 598 | 
            +
              { "declared_params" => declared(params, include_missing: false) }
         | 
| 599 | 
            +
            end
         | 
| 600 | 
            +
            ````
         | 
| 601 | 
            +
             | 
| 602 | 
            +
            **Request**
         | 
| 603 | 
            +
             | 
| 604 | 
            +
            ````bash
         | 
| 605 | 
            +
            curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d '{"user": {"first_name":"first name", "random": "never shown", "address": { "city": "SF"}}}'
         | 
| 606 | 
            +
            ````
         | 
| 607 | 
            +
             | 
| 608 | 
            +
            **Response with include_missing:false**
         | 
| 609 | 
            +
             | 
| 610 | 
            +
            ````json
         | 
| 611 | 
            +
            {
         | 
| 612 | 
            +
              "declared_params": {
         | 
| 613 | 
            +
                "user": {
         | 
| 614 | 
            +
                  "first_name": "first name",
         | 
| 615 | 
            +
                  "address": {
         | 
| 616 | 
            +
                    "city": "SF"
         | 
| 617 | 
            +
                  }
         | 
| 618 | 
            +
                }
         | 
| 619 | 
            +
              }
         | 
| 620 | 
            +
            }
         | 
| 621 | 
            +
            ````
         | 
| 622 | 
            +
             | 
| 623 | 
            +
            **Response with include_missing:true**
         | 
| 624 | 
            +
             | 
| 625 | 
            +
            ````json
         | 
| 626 | 
            +
            {
         | 
| 627 | 
            +
              "declared_params": {
         | 
| 628 | 
            +
                "user": {
         | 
| 629 | 
            +
                  "first_name": "first name",
         | 
| 630 | 
            +
                  "last_name": null,
         | 
| 631 | 
            +
                  "address": {
         | 
| 632 | 
            +
                    "city": "Zurich",
         | 
| 633 | 
            +
                    "region": null
         | 
| 634 | 
            +
                  }
         | 
| 635 | 
            +
                }
         | 
| 636 | 
            +
              }
         | 
| 637 | 
            +
            }
         | 
| 638 | 
            +
            ````
         | 
| 639 | 
            +
             | 
| 416 640 | 
             
            ## Parameter Validation and Coercion
         | 
| 417 641 |  | 
| 418 642 | 
             
            You can define validations and coercion options for your parameters using a `params` block.
         | 
| @@ -447,27 +671,25 @@ params do | |
| 447 671 | 
             
            end
         | 
| 448 672 | 
             
            ```
         | 
| 449 673 |  | 
| 450 | 
            -
             | 
| 451 | 
            -
             | 
| 452 | 
            -
            Default values are eagerly evaluated. Above `:non_random_number` will evaluate to the same
         | 
| 453 | 
            -
            number for each call to the endpoint of this `params` block. To have the default evaluate
         | 
| 454 | 
            -
            at calltime use a lambda, like `:random_number` above.
         | 
| 674 | 
            +
            Note that default values will be passed through to any validation options specified.
         | 
| 675 | 
            +
            The following example will always fail if `:color` is not explicitly provided.
         | 
| 455 676 |  | 
| 456 677 | 
             
            ```ruby
         | 
| 457 678 | 
             
            params do
         | 
| 458 | 
            -
               | 
| 679 | 
            +
              optional :color, type: String, default: 'blue', values: ['red', 'green']
         | 
| 459 680 | 
             
            end
         | 
| 460 681 | 
             
            ```
         | 
| 461 682 |  | 
| 462 | 
            -
            The  | 
| 463 | 
            -
            model you may want to restrict by hashtags that you have previously defined in the `HashTag` model.
         | 
| 683 | 
            +
            The correct implementation is to ensure the default value passes all validations.
         | 
| 464 684 |  | 
| 465 685 | 
             
            ```ruby
         | 
| 466 686 | 
             
            params do
         | 
| 467 | 
            -
               | 
| 687 | 
            +
              optional :color, type: String, default: 'blue', values: ['blue', 'red', 'green']
         | 
| 468 688 | 
             
            end
         | 
| 469 689 | 
             
            ```
         | 
| 470 690 |  | 
| 691 | 
            +
            #### Validation of Nested Parameters
         | 
| 692 | 
            +
             | 
| 471 693 | 
             
            Parameters can be nested using `group` or by calling `requires` or `optional` with a block.
         | 
| 472 694 | 
             
            In the above example, this means `params[:media][:url]` is required along with `params[:id]`,
         | 
| 473 695 | 
             
            and `params[:audio][:format]` is required only if `params[:audio]` is present.
         | 
| @@ -489,6 +711,66 @@ params do | |
| 489 711 | 
             
            end
         | 
| 490 712 | 
             
            ```
         | 
| 491 713 |  | 
| 714 | 
            +
            ### Built-in Validators
         | 
| 715 | 
            +
             | 
| 716 | 
            +
            #### `allow_blank`
         | 
| 717 | 
            +
             | 
| 718 | 
            +
            Parameters can be defined as `allow_blank`, ensuring that they contain a value. By default, `requires`
         | 
| 719 | 
            +
            only validates that a parameter was sent in the request, regardless its value. With `allow_blank`,
         | 
| 720 | 
            +
            empty values or whitespace only values are invalid.
         | 
| 721 | 
            +
             | 
| 722 | 
            +
            `allow_blank` can be combined with both `requires` and `optional`. If the parameter is required, it has to contain
         | 
| 723 | 
            +
            a value. If it's optional, it's possible to not send it in the request, but if it's being sent, it has to have
         | 
| 724 | 
            +
            some value, and not an empty string/only whitespaces.
         | 
| 725 | 
            +
             | 
| 726 | 
            +
             | 
| 727 | 
            +
            ```ruby
         | 
| 728 | 
            +
            params do
         | 
| 729 | 
            +
              requires :username, allow_blank: false
         | 
| 730 | 
            +
              optional :first_name, allow_blank: false
         | 
| 731 | 
            +
            end
         | 
| 732 | 
            +
            ```
         | 
| 733 | 
            +
             | 
| 734 | 
            +
            #### `values`
         | 
| 735 | 
            +
             | 
| 736 | 
            +
            Parameters can be restricted to a specific set of values with the `:values` option.
         | 
| 737 | 
            +
             | 
| 738 | 
            +
            Default values are eagerly evaluated. Above `:non_random_number` will evaluate to the same
         | 
| 739 | 
            +
            number for each call to the endpoint of this `params` block. To have the default evaluate
         | 
| 740 | 
            +
            lazily with each request use a lambda, like `:random_number` above.
         | 
| 741 | 
            +
             | 
| 742 | 
            +
            ```ruby
         | 
| 743 | 
            +
            params do
         | 
| 744 | 
            +
              requires :status, type: Symbol, values: [:not_started, :processing, :done]
         | 
| 745 | 
            +
              optional :numbers, type: Array[Integer], default: 1, values: [1, 2, 3, 5, 8]
         | 
| 746 | 
            +
            end
         | 
| 747 | 
            +
            ```
         | 
| 748 | 
            +
             | 
| 749 | 
            +
            The `:values` option can also be supplied with a `Proc`, evaluated lazily with each request.
         | 
| 750 | 
            +
            For example, given a status model you may want to restrict by hashtags that you have
         | 
| 751 | 
            +
            previously defined in the `HashTag` model.
         | 
| 752 | 
            +
             | 
| 753 | 
            +
            ```ruby
         | 
| 754 | 
            +
            params do
         | 
| 755 | 
            +
              requires :hashtag, type: String, values: -> { Hashtag.all.map(&:tag) }
         | 
| 756 | 
            +
            end
         | 
| 757 | 
            +
            ```
         | 
| 758 | 
            +
             | 
| 759 | 
            +
            #### `regexp`
         | 
| 760 | 
            +
             | 
| 761 | 
            +
            Parameters can be restricted to match a specific regular expression with the `:regexp` option. If the value
         | 
| 762 | 
            +
            is nil or does not match the regular expression an error will be returned. Note that this is true for both `requires`
         | 
| 763 | 
            +
            and `optional` parameters.
         | 
| 764 | 
            +
             | 
| 765 | 
            +
            ```ruby
         | 
| 766 | 
            +
            params do
         | 
| 767 | 
            +
              requires :email, regexp: /.+@.+/
         | 
| 768 | 
            +
            end
         | 
| 769 | 
            +
            ```
         | 
| 770 | 
            +
             | 
| 771 | 
            +
             | 
| 772 | 
            +
            #### `mutually_exclusive`
         | 
| 773 | 
            +
             | 
| 492 774 | 
             
            Parameters can be defined as `mutually_exclusive`, ensuring that they aren't present at the same time in a request.
         | 
| 493 775 |  | 
| 494 776 | 
             
            ```ruby
         | 
| @@ -514,6 +796,8 @@ end | |
| 514 796 |  | 
| 515 797 | 
             
            **Warning**: Never define mutually exclusive sets with any required params. Two mutually exclusive required params will mean params are never valid, thus making the endpoint useless. One required param mutually exclusive with an optional param will mean the latter is never valid.
         | 
| 516 798 |  | 
| 799 | 
            +
            #### `exactly_one_of`
         | 
| 800 | 
            +
             | 
| 517 801 | 
             
            Parameters can be defined as 'exactly_one_of', ensuring that exactly one parameter gets selected.
         | 
| 518 802 |  | 
| 519 803 | 
             
            ```ruby
         | 
| @@ -524,6 +808,8 @@ params do | |
| 524 808 | 
             
            end
         | 
| 525 809 | 
             
            ```
         | 
| 526 810 |  | 
| 811 | 
            +
            #### `at_least_one_of`
         | 
| 812 | 
            +
             | 
| 527 813 | 
             
            Parameters can be defined as 'at_least_one_of', ensuring that at least one parameter gets selected.
         | 
| 528 814 |  | 
| 529 815 | 
             
            ```ruby
         | 
| @@ -531,7 +817,51 @@ params do | |
| 531 817 | 
             
              optional :beer
         | 
| 532 818 | 
             
              optional :wine
         | 
| 533 819 | 
             
              optional :juice
         | 
| 534 | 
            -
               | 
| 820 | 
            +
              at_least_one_of :beer, :wine, :juice
         | 
| 821 | 
            +
            end
         | 
| 822 | 
            +
            ```
         | 
| 823 | 
            +
             | 
| 824 | 
            +
            #### `all_or_none_of`
         | 
| 825 | 
            +
             | 
| 826 | 
            +
            Parameters can be defined as 'all_or_none_of', ensuring that all or none of parameters gets selected.
         | 
| 827 | 
            +
             | 
| 828 | 
            +
            ```ruby
         | 
| 829 | 
            +
            params do
         | 
| 830 | 
            +
              optional :beer
         | 
| 831 | 
            +
              optional :wine
         | 
| 832 | 
            +
              optional :juice
         | 
| 833 | 
            +
              all_or_none_of :beer, :wine, :juice
         | 
| 834 | 
            +
            end
         | 
| 835 | 
            +
            ```
         | 
| 836 | 
            +
             | 
| 837 | 
            +
            #### Nested `mutually_exclusive`, `exactly_one_of`, `at_least_one_of`, `all_or_none_of`
         | 
| 838 | 
            +
             | 
| 839 | 
            +
            All of these methods can be used at any nested level.
         | 
| 840 | 
            +
             | 
| 841 | 
            +
            ```ruby
         | 
| 842 | 
            +
            params do
         | 
| 843 | 
            +
              requires :food do
         | 
| 844 | 
            +
                optional :meat
         | 
| 845 | 
            +
                optional :fish
         | 
| 846 | 
            +
                optional :rice
         | 
| 847 | 
            +
                at_least_one_of :meat, :fish, :rice
         | 
| 848 | 
            +
              end
         | 
| 849 | 
            +
              group :drink do
         | 
| 850 | 
            +
                optional :beer
         | 
| 851 | 
            +
                optional :wine
         | 
| 852 | 
            +
                optional :juice
         | 
| 853 | 
            +
                exactly_one_of :beer, :wine, :juice
         | 
| 854 | 
            +
              end
         | 
| 855 | 
            +
              optional :dessert do
         | 
| 856 | 
            +
                optional :cake
         | 
| 857 | 
            +
                optional :icecream
         | 
| 858 | 
            +
                mutually_exclusive :cake, :icecream
         | 
| 859 | 
            +
              end
         | 
| 860 | 
            +
              optional :recipe do
         | 
| 861 | 
            +
                optional :oil
         | 
| 862 | 
            +
                optional :meat
         | 
| 863 | 
            +
                all_or_none_of :oil, :meat
         | 
| 864 | 
            +
              end
         | 
| 535 865 | 
             
            end
         | 
| 536 866 | 
             
            ```
         | 
| 537 867 |  | 
| @@ -579,10 +909,10 @@ end | |
| 579 909 | 
             
            ### Custom Validators
         | 
| 580 910 |  | 
| 581 911 | 
             
            ```ruby
         | 
| 582 | 
            -
            class AlphaNumeric < Grape::Validations:: | 
| 912 | 
            +
            class AlphaNumeric < Grape::Validations::Base
         | 
| 583 913 | 
             
              def validate_param!(attr_name, params)
         | 
| 584 914 | 
             
                unless params[attr_name] =~ /^[[:alnum:]]+$/
         | 
| 585 | 
            -
                  raise Grape::Exceptions::Validation,  | 
| 915 | 
            +
                  raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: "must consist of alpha-numeric characters"
         | 
| 586 916 | 
             
                end
         | 
| 587 917 | 
             
              end
         | 
| 588 918 | 
             
            end
         | 
| @@ -597,10 +927,10 @@ end | |
| 597 927 | 
             
            You can also create custom classes that take parameters.
         | 
| 598 928 |  | 
| 599 929 | 
             
            ```ruby
         | 
| 600 | 
            -
            class Length < Grape::Validations:: | 
| 930 | 
            +
            class Length < Grape::Validations::Base
         | 
| 601 931 | 
             
              def validate_param!(attr_name, params)
         | 
| 602 932 | 
             
                unless params[attr_name].length <= @option
         | 
| 603 | 
            -
                  raise Grape::Exceptions::Validation,  | 
| 933 | 
            +
                  raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long"
         | 
| 604 934 | 
             
                end
         | 
| 605 935 | 
             
              end
         | 
| 606 936 | 
             
            end
         | 
| @@ -956,14 +1286,18 @@ end | |
| 956 1286 | 
             
            The following example specifies the entity to use in the `http_codes` definition.
         | 
| 957 1287 |  | 
| 958 1288 | 
             
            ```
         | 
| 959 | 
            -
            desc 'My Route' | 
| 1289 | 
            +
            desc 'My Route' do
         | 
| 1290 | 
            +
             failure [[408, 'Unauthorized', API::Error]]
         | 
| 1291 | 
            +
            end
         | 
| 960 1292 | 
             
            error!({ message: 'Unauthorized' }, 408)
         | 
| 961 1293 | 
             
            ```
         | 
| 962 1294 |  | 
| 963 1295 | 
             
            The following example specifies the presented entity explicitly in the error message.
         | 
| 964 1296 |  | 
| 965 1297 | 
             
            ```ruby
         | 
| 966 | 
            -
            desc 'My Route' | 
| 1298 | 
            +
            desc 'My Route' do
         | 
| 1299 | 
            +
             failure [[408, 'Unauthorized']]
         | 
| 1300 | 
            +
            end
         | 
| 967 1301 | 
             
            error!({ message: 'Unauthorized', with: API::Error }, 408)
         | 
| 968 1302 | 
             
            ```
         | 
| 969 1303 |  | 
| @@ -1176,16 +1510,115 @@ end | |
| 1176 1510 |  | 
| 1177 1511 | 
             
            ## API Formats
         | 
| 1178 1512 |  | 
| 1179 | 
            -
             | 
| 1513 | 
            +
            Your API can declare which content-types to support by using `content_type`. If you do not specify any, Grape will support
         | 
| 1514 | 
            +
            _XML_, _JSON_, _BINARY_, and _TXT_ content-types. The default format is `:txt`; you can change this with `default_format`.
         | 
| 1515 | 
            +
            Essentially, the two APIs below are equivalent.
         | 
| 1516 | 
            +
             | 
| 1517 | 
            +
            ```ruby
         | 
| 1518 | 
            +
            class Twitter::API < Grape::API
         | 
| 1519 | 
            +
              # no content_type declarations, so Grape uses the defaults
         | 
| 1520 | 
            +
            end
         | 
| 1521 | 
            +
             | 
| 1522 | 
            +
            class Twitter::API < Grape::API
         | 
| 1523 | 
            +
              # the following declarations are equivalent to the defaults
         | 
| 1524 | 
            +
             | 
| 1525 | 
            +
              content_type :xml, 'application/xml'
         | 
| 1526 | 
            +
              content_type :json, 'application/json'
         | 
| 1527 | 
            +
              content_type :binary, 'application/octet-stream'
         | 
| 1528 | 
            +
              content_type :txt, 'text/plain'
         | 
| 1529 | 
            +
             | 
| 1530 | 
            +
              default_format :txt
         | 
| 1531 | 
            +
            end
         | 
| 1532 | 
            +
            ```
         | 
| 1533 | 
            +
             | 
| 1534 | 
            +
            If you declare any `content_type` whatsoever, the Grape defaults will be overridden. For example, the following API will only
         | 
| 1535 | 
            +
            support the `:xml` and `:rss` content-types, but not `:txt`, `:json`, or `:binary`. Importantly, this means the `:txt`
         | 
| 1536 | 
            +
            default format is not supported! So, make sure to set a new `default_format`.
         | 
| 1537 | 
            +
             | 
| 1538 | 
            +
            ```ruby
         | 
| 1539 | 
            +
            class Twitter::API < Grape::API
         | 
| 1540 | 
            +
              content_type :xml, 'application/xml'
         | 
| 1541 | 
            +
              content_type :rss, 'application/xml+rss'
         | 
| 1542 | 
            +
             | 
| 1543 | 
            +
              default_format :xml
         | 
| 1544 | 
            +
            end
         | 
| 1545 | 
            +
            ```
         | 
| 1546 | 
            +
             | 
| 1547 | 
            +
            Serialization takes place automatically. For example, you do not have to call `to_json` in each JSON API endpoint
         | 
| 1548 | 
            +
            implementation. The response format (and thus the automatic serialization) is determined in the following order:
         | 
| 1549 | 
            +
            * Use the file extension, if specified. If the file is .json, choose the JSON format.
         | 
| 1550 | 
            +
            * Use the value of the `format` parameter in the query string, if specified.
         | 
| 1551 | 
            +
            * Use the format set by the `format` option, if specified.
         | 
| 1552 | 
            +
            * Attempt to find an acceptable format from the `Accept` header.
         | 
| 1553 | 
            +
            * Use the default format, if specified by the `default_format` option.
         | 
| 1554 | 
            +
            * Default to `:txt`.
         | 
| 1555 | 
            +
             | 
| 1556 | 
            +
            For example, consider the following API.
         | 
| 1557 | 
            +
             | 
| 1558 | 
            +
            ```ruby
         | 
| 1559 | 
            +
            class MultipleFormatAPI < Grape::API
         | 
| 1560 | 
            +
              content_type :xml, 'application/xml'
         | 
| 1561 | 
            +
              content_type :json, 'application/json'
         | 
| 1562 | 
            +
             | 
| 1563 | 
            +
              default_format :json
         | 
| 1564 | 
            +
             | 
| 1565 | 
            +
              get :hello do
         | 
| 1566 | 
            +
                { hello: 'world' }
         | 
| 1567 | 
            +
              end
         | 
| 1568 | 
            +
            end
         | 
| 1569 | 
            +
            ```
         | 
| 1570 | 
            +
             | 
| 1571 | 
            +
            * `GET /hello` (with an `Accept: */*` header) does not have an extension or a `format` parameter, so it will respond with
         | 
| 1572 | 
            +
              JSON (the default format).
         | 
| 1573 | 
            +
            * `GET /hello.xml` has a recognized extension, so it will respond with XML.
         | 
| 1574 | 
            +
            * `GET /hello?format=xml` has a recognized `format` parameter, so it will respond with XML.
         | 
| 1575 | 
            +
            * `GET /hello.xml?format=json` has a recognized extension (which takes precedence over the `format` parameter), so it will
         | 
| 1576 | 
            +
              respond with XML.
         | 
| 1577 | 
            +
            * `GET /hello.xls` (with an `Accept: */*` header) has an extension, but that extension is not recognized, so it will respond
         | 
| 1578 | 
            +
              with JSON (the default format).
         | 
| 1579 | 
            +
            * `GET /hello.xls` with an `Accept: application/xml` header has an unrecognized extension, but the `Accept` header
         | 
| 1580 | 
            +
              corresponds to a recognized format, so it will respond with XML.
         | 
| 1581 | 
            +
            * `GET /hello.xls` with an `Accept: text/plain` header has an unrecognized extension *and* an unrecognized `Accept` header,
         | 
| 1582 | 
            +
              so it will respond with JSON (the default format).
         | 
| 1583 | 
            +
             | 
| 1584 | 
            +
            You can override this process explicitly by specifying `env['api.format']` in the API itself.
         | 
| 1585 | 
            +
            For example, the following API will let you upload arbitrary files and return their contents as an attachment with the correct MIME type.
         | 
| 1586 | 
            +
             | 
| 1587 | 
            +
            ```ruby
         | 
| 1588 | 
            +
            class Twitter::API < Grape::API
         | 
| 1589 | 
            +
              post "attachment" do
         | 
| 1590 | 
            +
                filename = params[:file][:filename]
         | 
| 1591 | 
            +
                content_type MIME::Types.type_for(filename)[0].to_s
         | 
| 1592 | 
            +
                env['api.format'] = :binary # there's no formatter for :binary, data will be returned "as is"
         | 
| 1593 | 
            +
                header "Content-Disposition", "attachment; filename*=UTF-8''#{URI.escape(filename)}"
         | 
| 1594 | 
            +
                params[:file][:tempfile].read
         | 
| 1595 | 
            +
              end
         | 
| 1596 | 
            +
            end
         | 
| 1597 | 
            +
            ```
         | 
| 1598 | 
            +
             | 
| 1599 | 
            +
            You can have your API only respond to a single format with `format`. If you use this, the API will **not** respond to file
         | 
| 1600 | 
            +
            extensions. For example, consider the following API.
         | 
| 1601 | 
            +
             | 
| 1602 | 
            +
            ```ruby
         | 
| 1603 | 
            +
            class SingleFormatAPI < Grape::API
         | 
| 1604 | 
            +
              format :json
         | 
| 1180 1605 |  | 
| 1181 | 
            -
             | 
| 1606 | 
            +
              get :hello do
         | 
| 1607 | 
            +
                { hello: 'world' }
         | 
| 1608 | 
            +
              end
         | 
| 1609 | 
            +
            end
         | 
| 1610 | 
            +
            ```
         | 
| 1182 1611 |  | 
| 1183 | 
            -
             | 
| 1184 | 
            -
             | 
| 1612 | 
            +
            * `GET /hello` will respond with JSON.
         | 
| 1613 | 
            +
            * `GET /hello.xml`, `GET /hello.json`, `GET /hello.foobar`, or *any* other extension will respond with an HTTP 404 error code.
         | 
| 1614 | 
            +
            * `GET /hello?format=xml` will respond with an HTTP 406 error code, because the XML format specified by the request parameter
         | 
| 1615 | 
            +
              is not supported.
         | 
| 1616 | 
            +
            * `GET /hello` with an `Accept: application/xml` header will still respond with JSON, since it could not negotiate a
         | 
| 1617 | 
            +
              recognized content-type from the headers and JSON is the effective default.
         | 
| 1185 1618 |  | 
| 1186 | 
            -
            The following API will only respond to the JSON content-type and will not parse any other | 
| 1187 | 
            -
            `application/x-www-form-urlencoded`, `multipart/form-data`, `multipart/related` and | 
| 1188 | 
            -
            will fail with an HTTP 406 error code.
         | 
| 1619 | 
            +
            The formats apply to parsing, too. The following API will only respond to the JSON content-type and will not parse any other
         | 
| 1620 | 
            +
            input than `application/json`, `application/x-www-form-urlencoded`, `multipart/form-data`, `multipart/related` and
         | 
| 1621 | 
            +
            `multipart/mixed`. All other requests will fail with an HTTP 406 error code.
         | 
| 1189 1622 |  | 
| 1190 1623 | 
             
            ```ruby
         | 
| 1191 1624 | 
             
            class Twitter::API < Grape::API
         | 
| @@ -1238,45 +1671,13 @@ class Twitter::API < Grape::API | |
| 1238 1671 | 
             
            end
         | 
| 1239 1672 | 
             
            ```
         | 
| 1240 1673 |  | 
| 1241 | 
            -
            Built-in  | 
| 1674 | 
            +
            Built-in formatters are the following.
         | 
| 1242 1675 |  | 
| 1243 | 
            -
            * `:json | 
| 1676 | 
            +
            * `:json`: use object's `to_json` when available, otherwise call `MultiJson.dump`
         | 
| 1244 1677 | 
             
            * `:xml`: use object's `to_xml` when available, usually via `MultiXml`, otherwise call `to_s`
         | 
| 1245 1678 | 
             
            * `:txt`: use object's `to_txt` when available, otherwise `to_s`
         | 
| 1246 1679 | 
             
            * `:serializable_hash`: use object's `serializable_hash` when available, otherwise fallback to `:json`
         | 
| 1247 | 
            -
             | 
| 1248 | 
            -
            Use `default_format` to set the fallback format when the format could not be determined from the `Accept` header.
         | 
| 1249 | 
            -
            See below for the order for choosing the API format.
         | 
| 1250 | 
            -
             | 
| 1251 | 
            -
            ```ruby
         | 
| 1252 | 
            -
            class Twitter::API < Grape::API
         | 
| 1253 | 
            -
              default_format :json
         | 
| 1254 | 
            -
            end
         | 
| 1255 | 
            -
            ```
         | 
| 1256 | 
            -
             | 
| 1257 | 
            -
            The order for choosing the format is the following.
         | 
| 1258 | 
            -
             | 
| 1259 | 
            -
            * Use the file extension, if specified. If the file is .json, choose the JSON format.
         | 
| 1260 | 
            -
            * Use the value of the `format` parameter in the query string, if specified.
         | 
| 1261 | 
            -
            * Use the format set by the `format` option, if specified.
         | 
| 1262 | 
            -
            * Attempt to find an acceptable format from the `Accept` header.
         | 
| 1263 | 
            -
            * Use the default format, if specified by the `default_format` option.
         | 
| 1264 | 
            -
            * Default to `:txt`.
         | 
| 1265 | 
            -
             | 
| 1266 | 
            -
            You can override this process explicitly by specifying `env['api.format']` in the API itself.
         | 
| 1267 | 
            -
            For example, the following API will let you upload arbitrary files and return their contents as an attachment with the correct MIME type.
         | 
| 1268 | 
            -
             | 
| 1269 | 
            -
            ```ruby
         | 
| 1270 | 
            -
            class Twitter::API < Grape::API
         | 
| 1271 | 
            -
              post "attachment" do
         | 
| 1272 | 
            -
                filename = params[:file][:filename]
         | 
| 1273 | 
            -
                content_type MIME::Types.type_for(filename)[0].to_s
         | 
| 1274 | 
            -
                env['api.format'] = :binary # there's no formatter for :binary, data will be returned "as is"
         | 
| 1275 | 
            -
                header "Content-Disposition", "attachment; filename*=UTF-8''#{URI.escape(filename)}"
         | 
| 1276 | 
            -
                params[:file][:tempfile].read
         | 
| 1277 | 
            -
              end
         | 
| 1278 | 
            -
            end
         | 
| 1279 | 
            -
            ```
         | 
| 1680 | 
            +
            * `:binary`: data will be returned "as is"
         | 
| 1280 1681 |  | 
| 1281 1682 | 
             
            ### JSONP
         | 
| 1282 1683 |  | 
| @@ -1398,9 +1799,9 @@ module API | |
| 1398 1799 | 
             
              class Statuses < Grape::API
         | 
| 1399 1800 | 
             
                version 'v1'
         | 
| 1400 1801 |  | 
| 1401 | 
            -
                desc 'Statuses index' | 
| 1802 | 
            +
                desc 'Statuses index' do
         | 
| 1402 1803 | 
             
                  params: API::Entities::Status.documentation
         | 
| 1403 | 
            -
                 | 
| 1804 | 
            +
                end
         | 
| 1404 1805 | 
             
                get '/statuses' do
         | 
| 1405 1806 | 
             
                  statuses = Status.all
         | 
| 1406 1807 | 
             
                  type = current_user.admin? ? :full : :default
         | 
| @@ -1486,6 +1887,32 @@ You can use [Active Model Serializers](https://github.com/rails-api/active_model | |
| 1486 1887 | 
             
            [grape-active_model_serializers](https://github.com/jrhe/grape-active_model_serializers) gem, which defines a custom Grape AMS
         | 
| 1487 1888 | 
             
            formatter.
         | 
| 1488 1889 |  | 
| 1890 | 
            +
            ## Sending Raw or No Data
         | 
| 1891 | 
            +
             | 
| 1892 | 
            +
            In general, use the binary format to send raw data.
         | 
| 1893 | 
            +
             | 
| 1894 | 
            +
            ```ruby
         | 
| 1895 | 
            +
            class API < Grape::API
         | 
| 1896 | 
            +
              get '/file' do
         | 
| 1897 | 
            +
                content_type 'application/octet-stream'
         | 
| 1898 | 
            +
                File.binread 'file.bin'
         | 
| 1899 | 
            +
              end
         | 
| 1900 | 
            +
            end
         | 
| 1901 | 
            +
            ```
         | 
| 1902 | 
            +
             | 
| 1903 | 
            +
            You can also set the response body explicitly with `body`.
         | 
| 1904 | 
            +
             | 
| 1905 | 
            +
            ```ruby
         | 
| 1906 | 
            +
            class API < Grape::API
         | 
| 1907 | 
            +
              get '/' do
         | 
| 1908 | 
            +
                content_type 'text/plain'
         | 
| 1909 | 
            +
                body 'Hello World'
         | 
| 1910 | 
            +
                # return value ignored
         | 
| 1911 | 
            +
              end
         | 
| 1912 | 
            +
            end
         | 
| 1913 | 
            +
            ```
         | 
| 1914 | 
            +
             | 
| 1915 | 
            +
            Use `body false` to return `204 No Content` without any data or content-type.
         | 
| 1489 1916 |  | 
| 1490 1917 | 
             
            ## Authentication
         | 
| 1491 1918 |  | 
| @@ -1515,7 +1942,7 @@ Grape can use custom Middleware for authentication. How to implement these | |
| 1515 1942 | 
             
            Middleware have a look at `Rack::Auth::Basic` or similar implementations.
         | 
| 1516 1943 |  | 
| 1517 1944 |  | 
| 1518 | 
            -
            For registering a  | 
| 1945 | 
            +
            For registering a Middleware you need the following options:
         | 
| 1519 1946 |  | 
| 1520 1947 | 
             
            * `label` - the name for your authenticator to use it later
         | 
| 1521 1948 | 
             
            * `MiddlewareClass` - the MiddlewareClass to use for authentication
         | 
| @@ -1529,7 +1956,7 @@ Example: | |
| 1529 1956 | 
             
            Grape::Middleware::Auth::Strategies.add(:my_auth, AuthMiddleware, ->(options) { [options[:realm]] } )
         | 
| 1530 1957 |  | 
| 1531 1958 |  | 
| 1532 | 
            -
            auth :my_auth  | 
| 1959 | 
            +
            auth :my_auth, { realm: 'Test Api'} do |credentials|
         | 
| 1533 1960 | 
             
              # lookup the user's password here
         | 
| 1534 1961 | 
             
              { 'user1' => 'password1' }[username]
         | 
| 1535 1962 | 
             
            end
         | 
| @@ -1540,26 +1967,34 @@ Use [warden-oauth2](https://github.com/opperator/warden-oauth2) or [rack-oauth2] | |
| 1540 1967 |  | 
| 1541 1968 | 
             
            ## Describing and Inspecting an API
         | 
| 1542 1969 |  | 
| 1543 | 
            -
            Grape routes can be reflected at runtime. This can notably be useful for generating
         | 
| 1544 | 
            -
             | 
| 1970 | 
            +
            Grape routes can be reflected at runtime. This can notably be useful for generating documentation.
         | 
| 1971 | 
            +
             | 
| 1972 | 
            +
            Grape exposes arrays of API versions and compiled routes. Each route contains a `route_prefix`, `route_version`, `route_namespace`, `route_method`, `route_path` and `route_params`. You can add custom route settings to the route metadata with `route_setting`.
         | 
| 1973 | 
            +
             | 
| 1974 | 
            +
            ```ruby
         | 
| 1975 | 
            +
            class TwitterAPI < Grape::API
         | 
| 1976 | 
            +
              version 'v1'
         | 
| 1977 | 
            +
              desc "Includes custom settings."
         | 
| 1978 | 
            +
              route_setting :custom, key: 'value'
         | 
| 1979 | 
            +
              get do
         | 
| 1545 1980 |  | 
| 1546 | 
            -
             | 
| 1547 | 
            -
             | 
| 1548 | 
            -
             | 
| 1549 | 
            -
             | 
| 1550 | 
            -
             | 
| 1981 | 
            +
              end
         | 
| 1982 | 
            +
            end
         | 
| 1983 | 
            +
            ```
         | 
| 1984 | 
            +
             | 
| 1985 | 
            +
            Examine the routes at runtime.
         | 
| 1551 1986 |  | 
| 1552 1987 | 
             
            ```ruby
         | 
| 1553 1988 | 
             
            TwitterAPI::versions # yields [ 'v1', 'v2' ]
         | 
| 1554 1989 | 
             
            TwitterAPI::routes # yields an array of Grape::Route objects
         | 
| 1555 | 
            -
            TwitterAPI::routes[0].route_version #  | 
| 1556 | 
            -
            TwitterAPI::routes[0].route_description #  | 
| 1990 | 
            +
            TwitterAPI::routes[0].route_version # => 'v1'
         | 
| 1991 | 
            +
            TwitterAPI::routes[0].route_description # => 'Includes custom settings.'
         | 
| 1992 | 
            +
            TwitterAPI::routes[0].route_settings[:custom] # => { key: 'value' }
         | 
| 1557 1993 | 
             
            ```
         | 
| 1558 1994 |  | 
| 1559 1995 | 
             
            ## Current Route and Endpoint
         | 
| 1560 1996 |  | 
| 1561 | 
            -
            It's possible to retrieve the information about the current route from within an API
         | 
| 1562 | 
            -
            call with `route`.
         | 
| 1997 | 
            +
            It's possible to retrieve the information about the current route from within an API call with `route`.
         | 
| 1563 1998 |  | 
| 1564 1999 | 
             
            ```ruby
         | 
| 1565 2000 | 
             
            class MyAPI < Grape::API
         | 
| @@ -1703,6 +2138,35 @@ specification and using the `PATH_INFO` Rack environment variable, using | |
| 1703 2138 | 
             
            `env["PATH_INFO"]`. This will hold everything that comes after the '/statuses/'
         | 
| 1704 2139 | 
             
            part.
         | 
| 1705 2140 |  | 
| 2141 | 
            +
            # Using Custom Middleware
         | 
| 2142 | 
            +
             | 
| 2143 | 
            +
            ## Rails Middleware
         | 
| 2144 | 
            +
             | 
| 2145 | 
            +
            Note that when you're using Grape mounted on Rails you don't have to use Rails middleware because it's already included into your middleware stack.
         | 
| 2146 | 
            +
            You only have to implement the helpers to access the specific `env` variable.
         | 
| 2147 | 
            +
             | 
| 2148 | 
            +
            ### Remote IP
         | 
| 2149 | 
            +
             | 
| 2150 | 
            +
            By default you can access remote IP with `request.ip`. This is the remote IP address implemented by Rack. Sometimes it is desirable to get the remote IP [Rails-style](http://stackoverflow.com/questions/10997005/whats-the-difference-between-request-remote-ip-and-request-ip-in-rails) with `ActionDispatch::RemoteIp`.
         | 
| 2151 | 
            +
             | 
| 2152 | 
            +
            Add `gem 'actionpack'` to your Gemfile and `require 'action_dispatch/middleware/remote_ip.rb'`. Use the middleware in your API and expose a `client_ip` helper. See [this documentation](http://api.rubyonrails.org/classes/ActionDispatch/RemoteIp.html) for additional options.
         | 
| 2153 | 
            +
             | 
| 2154 | 
            +
            ```ruby
         | 
| 2155 | 
            +
            class API < Grape::API
         | 
| 2156 | 
            +
              use ActionDispatch::RemoteIp
         | 
| 2157 | 
            +
             | 
| 2158 | 
            +
              helpers do
         | 
| 2159 | 
            +
                def client_ip
         | 
| 2160 | 
            +
                  env["action_dispatch.remote_ip"].to_s
         | 
| 2161 | 
            +
                end
         | 
| 2162 | 
            +
              end
         | 
| 2163 | 
            +
             | 
| 2164 | 
            +
              get :remopte_ip do
         | 
| 2165 | 
            +
                { ip: client_ip }
         | 
| 2166 | 
            +
              end
         | 
| 2167 | 
            +
            end
         | 
| 2168 | 
            +
            ```
         | 
| 2169 | 
            +
             | 
| 1706 2170 | 
             
            ## Writing Tests
         | 
| 1707 2171 |  | 
| 1708 2172 | 
             
            You can test a Grape API with RSpec by making HTTP requests and examining the response.
         | 
| @@ -1722,17 +2186,17 @@ describe Twitter::API do | |
| 1722 2186 | 
             
              end
         | 
| 1723 2187 |  | 
| 1724 2188 | 
             
              describe Twitter::API do
         | 
| 1725 | 
            -
                describe "GET /api/ | 
| 2189 | 
            +
                describe "GET /api/statuses/public_timeline" do
         | 
| 1726 2190 | 
             
                  it "returns an empty array of statuses" do
         | 
| 1727 | 
            -
                    get "/api/ | 
| 2191 | 
            +
                    get "/api/statuses/public_timeline"
         | 
| 1728 2192 | 
             
                    expect(last_response.status).to eq(200)
         | 
| 1729 2193 | 
             
                    expect(JSON.parse(last_response.body)).to eq []
         | 
| 1730 2194 | 
             
                  end
         | 
| 1731 2195 | 
             
                end
         | 
| 1732 | 
            -
                describe "GET /api/ | 
| 2196 | 
            +
                describe "GET /api/statuses/:id" do
         | 
| 1733 2197 | 
             
                  it "returns a status by id" do
         | 
| 1734 2198 | 
             
                    status = Status.create!
         | 
| 1735 | 
            -
                    get "/api/ | 
| 2199 | 
            +
                    get "/api/statuses/#{status.id}"
         | 
| 1736 2200 | 
             
                    expect(last_response.body).to eq status.to_json
         | 
| 1737 2201 | 
             
                  end
         | 
| 1738 2202 | 
             
                end
         | 
| @@ -1744,17 +2208,17 @@ end | |
| 1744 2208 |  | 
| 1745 2209 | 
             
            ```ruby
         | 
| 1746 2210 | 
             
            describe Twitter::API do
         | 
| 1747 | 
            -
              describe "GET /api/ | 
| 2211 | 
            +
              describe "GET /api/statuses/public_timeline" do
         | 
| 1748 2212 | 
             
                it "returns an empty array of statuses" do
         | 
| 1749 | 
            -
                  get "/api/ | 
| 2213 | 
            +
                  get "/api/statuses/public_timeline"
         | 
| 1750 2214 | 
             
                  expect(response.status).to eq(200)
         | 
| 1751 2215 | 
             
                  expect(JSON.parse(response.body)).to eq []
         | 
| 1752 2216 | 
             
                end
         | 
| 1753 2217 | 
             
              end
         | 
| 1754 | 
            -
              describe "GET /api/ | 
| 2218 | 
            +
              describe "GET /api/statuses/:id" do
         | 
| 1755 2219 | 
             
                it "returns a status by id" do
         | 
| 1756 2220 | 
             
                  status = Status.create!
         | 
| 1757 | 
            -
                  get "/api/ | 
| 2221 | 
            +
                  get "/api/statuses/#{status.id}"
         | 
| 1758 2222 | 
             
                  expect(response.body).to eq status.to_json
         | 
| 1759 2223 | 
             
                end
         | 
| 1760 2224 | 
             
              end
         | 
| @@ -1766,9 +2230,7 @@ In Rails, HTTP request tests would go into the `spec/requests` group. You may wa | |
| 1766 2230 |  | 
| 1767 2231 | 
             
            ```ruby
         | 
| 1768 2232 | 
             
            RSpec.configure do |config|
         | 
| 1769 | 
            -
              config.include RSpec::Rails::RequestExampleGroup, type: :request,  | 
| 1770 | 
            -
                file_path: /spec\/api/
         | 
| 1771 | 
            -
              }
         | 
| 2233 | 
            +
              config.include RSpec::Rails::RequestExampleGroup, type: :request, file_path: /spec\/api/
         | 
| 1772 2234 | 
             
            end
         | 
| 1773 2235 | 
             
            ```
         | 
| 1774 2236 |  | 
| @@ -1799,7 +2261,11 @@ end | |
| 1799 2261 |  | 
| 1800 2262 | 
             
            ## Reloading API Changes in Development
         | 
| 1801 2263 |  | 
| 1802 | 
            -
            ###  | 
| 2264 | 
            +
            ### Reloading in Rack Applications
         | 
| 2265 | 
            +
             | 
| 2266 | 
            +
            Use [grape-reload](https://github.com/AlexYankee/grape-reload).
         | 
| 2267 | 
            +
             | 
| 2268 | 
            +
            ### Reloading in Rails Applications
         | 
| 1803 2269 |  | 
| 1804 2270 | 
             
            Add API paths to `config/application.rb`.
         | 
| 1805 2271 |  |