-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace hashie mash with hash #1594
Changes from all commits
a908eb7
1afdc91
162f28c
57f4545
1787cb7
71052c8
790443b
d9e8ed0
bbb88e3
eabe213
2a21427
e54e2d0
2201d15
85e02c7
d7c1daa
2491071
f4aeb9d
dc07f38
6c2d614
abae16c
247869b
6e5964b
2ddaa42
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -509,7 +509,7 @@ post 'users/signup' do | |
end | ||
```` | ||
|
||
If we do not specify any params, `declared` will return an empty `Hashie::Mash` instance. | ||
If we do not specify any params, `declared` will return an empty `ActiveSupport::HashWithIndifferentAccess` hash. | ||
|
||
**Request** | ||
|
||
|
@@ -562,10 +562,10 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d | |
} | ||
```` | ||
|
||
The returned hash is a `Hashie::Mash` instance, allowing you to access parameters via dot notation: | ||
The returned hash is a `ActiveSupport::HashWithIndifferentAccess` hash. | ||
|
||
```ruby | ||
declared(params).user == declared(params)['user'] | ||
declared(params)[:user] == declared(params)['user'] | ||
``` | ||
|
||
|
||
|
@@ -797,6 +797,22 @@ params do | |
end | ||
``` | ||
|
||
By default Grape 1.x presents the parameters to the endpoint as an | ||
`ActiveSupport::HashWithIndifferentAccess`. This is a change from 0.x where a | ||
Hashie::Mash was previously presented. | ||
|
||
To restore the previous behaviour check out [UPGRADING](UPGRADING.md). | ||
|
||
If you would rather have the parameters presented as a plain old Ruby Hash you | ||
can specify this using build_with in the params block; | ||
|
||
```ruby | ||
params do | ||
build_with Grape::Extensions::Hash::ParamBuilder | ||
optional :color, type: String, default: 'blue', values: ['blue', 'red', 'green'] | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document how to configure this globally with |
||
``` | ||
|
||
### Supported Parameter Types | ||
|
||
The following are all valid types, supported out of the box by Grape: | ||
|
@@ -905,11 +921,14 @@ params do | |
requires :avatar, type: File | ||
end | ||
post '/' do | ||
# Parameter will be wrapped using Hashie: | ||
params.avatar.filename # => 'avatar.png' | ||
params.avatar.type # => 'image/png' | ||
params.avatar.tempfile # => #<File> | ||
# Parameter will be wrapped using HashWithIndifferentAccess: | ||
params[:avatar][:filename] # => 'avatar.png' | ||
params['avatar']['avatar'] # => 'image/png' | ||
params[:avatar][:tempfile] # => #<File> | ||
end | ||
|
||
By default `params` hash keys can accesed with a string or a symbol | ||
`:avatar` and `"avatar"` are considered to be the same. | ||
``` | ||
|
||
### First-Class `JSON` Types | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,19 @@ | ||
Upgrading Grape | ||
=============== | ||
### Upgrading to >= 1.0.0 | ||
Prior to this version the endpoint was presented with params in the form of a Hashie::Mash. From 1.0.0 upwards Grape presents the parameters to the endpoint as an | ||
ActiveSupport::HashWithIndifferentAccess. | ||
|
||
To restore the previous behaviour you can specify Hashie::Mash using build_with in the params block; | ||
|
||
```ruby | ||
params do | ||
build_with Grape::Extensions::Hashie::Mash::ParamBuilder | ||
optional :color, type: String, default: 'blue', values: ['blue', 'red', 'green'] | ||
end | ||
``` | ||
|
||
The various options are documented in [Grape::DSL::Parameters](lib/grape/dsl/parameters.rb) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't explain how to do this globally or for an entire API. I have a 500 endpoints, I don't think I can do this everywhere :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you look at the implementation in dsl/parameters. This is actually my first outing with Grape so I wasn't 100% sure about the inheritable parameters so I'd appreciate some eyes on that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks OK to me, just need a way to do this globally. I'm not in love with Either way we need something where I can do this for an entire API. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So currently I've just got build_with defined in lib/grape/dsl/parameters.rb which is fine for the syntax in the local params block. Can you suggest how & where you would like this in Global? I'm on very limited time for this so a big sign post would help. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dblock @namusyaka There are a lot of getter/setters in DSL::Settings, right now I do not have the time to read through all the code and decipher which one to use and how they interact with each other so I'm going to need direction. I too am not delighted with build_with but couldn't come up with anything better and it kind of made sense in the context of the params block. I don't think it much sense in a global context so very receptive to suggestions of what to call it and where to put it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I'd want a mixin, so something like class API < Grape::API
include Grape::SomethingSomething::Params::Hashie::Mash
end One way it could work is by overriding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I couldn't find a clean way via composition as you're mixing into API, but Request creates the params when Endpoint is mounted in API so going that route I ended up passing the class to instantiate through Endpoint and onto Request. Which pretty convoluted given we have a mechanism for sharing parameters across API and Endpoint via the Settings mixin. |
||
|
||
### Upgrading to >= 0.19.1 | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
module Grape | ||
module Extensions | ||
class DeepMergeableHash < ::Hash | ||
def deep_merge!(other_hash) | ||
other_hash.each_pair do |current_key, other_value| | ||
this_value = self[current_key] | ||
|
||
self[current_key] = if this_value.is_a?(::Hash) && other_value.is_a?(::Hash) | ||
this_value.deep_merge(other_value) | ||
else | ||
other_value | ||
end | ||
end | ||
|
||
self | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
module Grape | ||
module Extensions | ||
module DeepSymbolizeHash | ||
def self.deep_symbolize_keys_in(object) | ||
case object | ||
when ::Hash | ||
object.each_with_object({}) do |(key, value), new_hash| | ||
new_hash[symbolize_key(key)] = deep_symbolize_keys_in(value) | ||
end | ||
when ::Array | ||
object.map { |element| deep_symbolize_keys_in(element) } | ||
else | ||
object | ||
end | ||
end | ||
|
||
def self.symbolize_key(key) | ||
key.respond_to?(:to_sym) ? key.to_sym : key | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
require_relative 'deep_mergeable_hash' | ||
require_relative 'deep_symbolize_hash' | ||
module Grape | ||
module Extensions | ||
module Hash | ||
module ParamBuilder | ||
def build_params | ||
params = Grape::Extensions::DeepMergeableHash[rack_params] | ||
params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS] | ||
post_process_params(params) | ||
end | ||
|
||
def post_process_params(params) | ||
Grape::Extensions::DeepSymbolizeHash.deep_symbolize_keys_in(params) | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
module Grape | ||
module Extensions | ||
module HashWithIndifferentAccess | ||
def params_builder | ||
Grape::Extensions::HashWithIndifferentAccess::ParamBuilder | ||
end | ||
|
||
module ParamBuilder | ||
def build_params | ||
params = ActiveSupport::HashWithIndifferentAccess[rack_params] | ||
params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS] | ||
params | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
require 'hashie' | ||
module Grape | ||
module Extensions | ||
module Hashie | ||
module Mash | ||
def params_builder | ||
Grape::Extensions::Hashie::Mash::ParamBuilder | ||
end | ||
|
||
module ParamBuilder | ||
def build_params | ||
params = ::Hashie::Mash.new(rack_params) | ||
params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS] | ||
params | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should still work, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a HashWithIndifferentAccess so I wouldn't expect to be able to access :user as a method only with a key.