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
Better Request Parsing Parameters #331
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Issue: #310 The framework should be able to parse JSON request body appropriately by returning a `JSON::Any` object. Currently, there is a bug when trying to parse JSON parameters from the body of a request where nested JSON payload is not being parsed correctly ```crystal { "test": "test", "address": { "city": "New York" } params["address"].as(Hash)["city"] ``` Params is now a custom Hash of the following signature `Hash(String | Symbol, Amber::Router::ParamsType)` or `Amber::Router::ParamsHash.new` To give more context all parameters where being parsed using the **HTTP::Params.parse** method which returns an object of type **Hash(String, Array(String))** this caused issues when parsing JSON params from the body, It turns out that nested JSON keys where being parsed as a string. Basically, all `params` values are currently returning as a string. With the changes presented in this PR users can now define model objects with JSON mapping that should be evaluated correctly based on the mapping defined. So for instance: ```crystal params["user_id"].as(Int64) => 123 params["address"].as(Hash).each ... params["user"].as(User) => User.name User.from_json(params["user"]) => User.name ``` **Controller** The controller now generates the app using params.validation similar to Rails strong params. It adds a method to the Controller and overloads the Granite initializer and set_attributes methods. ```crystal private def animal_params params.validation do required("name") { |v| v.str? & !v.empty? } end end animal = Animal.new(animal_params.validate!) ``` Model Models generate for the Granite::ORM now includes the following line include Amber::Models::Granite this will allow models to be populated with the controller params using the params.validations. The reason this is added here and not to the Granite::ORM repo is to keep Granite loosely coupled from any framework since the params.validation is specific to amber. ```crystal class Animal < Granite::ORM include Amber::Models::Granite end ```
eliasjpr
force-pushed
the
ep/fixes-params-json-parsing
branch
from
October 26, 2017 23:58
c2f8de7
to
ff44e8f
Compare
eliasjpr
requested review from
elorest,
migeorge,
fridgerator,
veelenga,
c910335 and
a team
October 27, 2017 00:11
faustinoaq
suggested changes
Oct 27, 2017
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.
Looks good, 👍
src/amber/cli/templates/auth.cr
Outdated
@@ -25,7 +25,7 @@ module Amber::CLI | |||
@timestamp = Time.now.to_s("%Y%m%d%H%M%S") | |||
@primary_key = primary_key | |||
@visible_fields = @fields.reject(&.hidden).map(&.name) | |||
|
|||
add_routes :web, <<-ROUTES | |||
get "/signin", SessionController, :new | |||
post "/session", SessionController, :create |
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.
Indentation issue
marksiemers
pushed a commit
to marksiemers/amber
that referenced
this pull request
Oct 28, 2017
* Better Request Parsing Parameters Issue: amberframework#310 The framework should be able to parse JSON request body appropriately by returning a `JSON::Any` object. Currently, there is a bug when trying to parse JSON parameters from the body of a request where nested JSON payload is not being parsed correctly ```crystal { "test": "test", "address": { "city": "New York" } params["address"].as(Hash)["city"] ``` Params is now a custom Hash of the following signature `Hash(String | Symbol, Amber::Router::ParamsType)` or `Amber::Router::ParamsHash.new` To give more context all parameters where being parsed using the **HTTP::Params.parse** method which returns an object of type **Hash(String, Array(String))** this caused issues when parsing JSON params from the body, It turns out that nested JSON keys where being parsed as a string. Basically, all `params` values are currently returning as a string. With the changes presented in this PR users can now define model objects with JSON mapping that should be evaluated correctly based on the mapping defined. So for instance: ```crystal params["user_id"].as(Int64) => 123 params["address"].as(Hash).each ... params["user"].as(User) => User.name User.from_json(params["user"]) => User.name ``` **Controller** The controller now generates the app using params.validation similar to Rails strong params. It adds a method to the Controller and overloads the Granite initializer and set_attributes methods. ```crystal private def animal_params params.validation do required("name") { |v| v.str? & !v.empty? } end end animal = Animal.new(animal_params.validate!) ``` Model Models generate for the Granite::ORM now includes the following line include Amber::Models::Granite this will allow models to be populated with the controller params using the params.validations. The reason this is added here and not to the Granite::ORM repo is to keep Granite loosely coupled from any framework since the params.validation is specific to amber. ```crystal class Animal < Granite::ORM include Amber::Models::Granite end ``` * fixup! Better Request Parsing Parameters
This was referenced Nov 12, 2017
elorest
pushed a commit
that referenced
this pull request
Nov 17, 2017
* Better Request Parsing Parameters Issue: #310 The framework should be able to parse JSON request body appropriately by returning a `JSON::Any` object. Currently, there is a bug when trying to parse JSON parameters from the body of a request where nested JSON payload is not being parsed correctly ```crystal { "test": "test", "address": { "city": "New York" } params["address"].as(Hash)["city"] ``` Params is now a custom Hash of the following signature `Hash(String | Symbol, Amber::Router::ParamsType)` or `Amber::Router::ParamsHash.new` To give more context all parameters where being parsed using the **HTTP::Params.parse** method which returns an object of type **Hash(String, Array(String))** this caused issues when parsing JSON params from the body, It turns out that nested JSON keys where being parsed as a string. Basically, all `params` values are currently returning as a string. With the changes presented in this PR users can now define model objects with JSON mapping that should be evaluated correctly based on the mapping defined. So for instance: ```crystal params["user_id"].as(Int64) => 123 params["address"].as(Hash).each ... params["user"].as(User) => User.name User.from_json(params["user"]) => User.name ``` **Controller** The controller now generates the app using params.validation similar to Rails strong params. It adds a method to the Controller and overloads the Granite initializer and set_attributes methods. ```crystal private def animal_params params.validation do required("name") { |v| v.str? & !v.empty? } end end animal = Animal.new(animal_params.validate!) ``` Model Models generate for the Granite::ORM now includes the following line include Amber::Models::Granite this will allow models to be populated with the controller params using the params.validations. The reason this is added here and not to the Granite::ORM repo is to keep Granite loosely coupled from any framework since the params.validation is specific to amber. ```crystal class Animal < Granite::ORM include Amber::Models::Granite end ``` * fixup! Better Request Parsing Parameters
elorest
pushed a commit
that referenced
this pull request
Nov 17, 2017
* Better Request Parsing Parameters Issue: #310 The framework should be able to parse JSON request body appropriately by returning a `JSON::Any` object. Currently, there is a bug when trying to parse JSON parameters from the body of a request where nested JSON payload is not being parsed correctly ```crystal { "test": "test", "address": { "city": "New York" } params["address"].as(Hash)["city"] ``` Params is now a custom Hash of the following signature `Hash(String | Symbol, Amber::Router::ParamsType)` or `Amber::Router::ParamsHash.new` To give more context all parameters where being parsed using the **HTTP::Params.parse** method which returns an object of type **Hash(String, Array(String))** this caused issues when parsing JSON params from the body, It turns out that nested JSON keys where being parsed as a string. Basically, all `params` values are currently returning as a string. With the changes presented in this PR users can now define model objects with JSON mapping that should be evaluated correctly based on the mapping defined. So for instance: ```crystal params["user_id"].as(Int64) => 123 params["address"].as(Hash).each ... params["user"].as(User) => User.name User.from_json(params["user"]) => User.name ``` **Controller** The controller now generates the app using params.validation similar to Rails strong params. It adds a method to the Controller and overloads the Granite initializer and set_attributes methods. ```crystal private def animal_params params.validation do required("name") { |v| v.str? & !v.empty? } end end animal = Animal.new(animal_params.validate!) ``` Model Models generate for the Granite::ORM now includes the following line include Amber::Models::Granite this will allow models to be populated with the controller params using the params.validations. The reason this is added here and not to the Granite::ORM repo is to keep Granite loosely coupled from any framework since the params.validation is specific to amber. ```crystal class Animal < Granite::ORM include Amber::Models::Granite end ``` * fixup! Better Request Parsing Parameters Former-commit-id: 9d9ccd6
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Edited by @eliasjpr
Description of the Change
The framework should be able to parse JSON request body appropriately by
returning a
JSON::Any
object.Currently, there is a bug when trying to parse JSON parameters from the
body of a request where nested JSON payload is not being parsed correctly
Params is now a custom Hash of the following signature
Hash(String | Symbol, Amber::Router::ParamsType)
orAmber::Router::ParamsHash.new
To give more context all parameters where being parsed using the
HTTP::Params.parse method which returns an object of type
Hash(String, Array(String)) this caused issues when parsing
JSON params from the body, It turns out that nested JSON keys where
being parsed as a string. Basically, all
params
values are currentlyreturning as a string.
With the changes presented in this PR users can now define model objects
with JSON mapping that should be evaluated correctly based on the mapping
defined.
Controller
The controller now generates the app using params.validation similar to
Rails strong params. It adds a method to the Controller and overloads the
Granite initializer and set_attributes methods.
Alternate Designs
It would be nice to specify a type that can be cast automatically
Benefits
.to_i
,.to_f
,.to_s
or traverse the JSON usingjson = JSON.parse(params["some_key"])
Possible Drawbacks
-Fear something can break
Example app using this branch
https://github.com/eliasjpr/params-test-app