4

My Grape API accepts json format and I have method that accepts JSON as parameter:

desc 'JSON test'
params do
  requires :json, type: JSON
end
post :json_test do
  json = params[:json]
  {result: json}
end

When I make request via postman, parameters are raw with application/json content type:

{
   "json": {"test": "test"}
}

When I send this I get error message:

"json is invalid"

However, when I send it like this:

{
  "json": "{\"test\": \"test\"}"
}

It shows me correct response:

{
 "result": {
   "test": "test"
  }
}

Why this is happening? When I make type Hash the first variant works, but if I want to send Array of hashes/jsons? I kniw that Grape does not support Array[Hash] type.

Mr.D
  • 7,353
  • 13
  • 60
  • 119

2 Answers2

7

grape parses the application/json data before it reaches your params block.


in this block:

params do
  requires :json, type: JSON
end

you are telling grape that your :json param should contain a JSON string.

so when you send this:

{
   "json": {"test": "test"}
}

json contains

{"test": "test"} 

which is sees as a hash, not a valid JSON string hence our error.

but when you send this

{
  "json": "{\"test\": \"test\"}"
}

json contains

"{\"test\": \"test\"}"

which is a valid JSON string, which it will then happily parse into a hash for you.


If you want to use

{
   "json": {"test": "test"}
}

in your post request, Your params block should be something like this:

params do
    requires :json, type: Hash #<-- Hash here instead of JSON since json data has already been parsed into a Hash
end
KorreyD
  • 1,274
  • 8
  • 15
  • This works. However, if I want to send array of json objects it won't work, because Grape does not have `Array[Hash]`, only `Array[JSON]` type. – Mr.D Apr 18 '16 at 09:42
  • 1
    instead of "Array[Hash]" you will just use "Array", as the documentation states that type: Array treats nested parameters as "values of hashes in an array". If you use type Array[JSON] then the param you are specifying the type of must be a valid json string as stated above. – KorreyD Apr 18 '16 at 14:38
1

If you want to parse a classic JSON with Grape using this:

params do
  requires :groceries, type: JSON
end

then send a JSON with a single key, that has a value of type String (a JSON String).

Examples for sending the JSON:

Use as raw parameter:

{ "groceries_key": "{\"fruits\": { \"apples\": 2 }, \"vegetables\": { \"carrets\": \"a few\" }}" }

Use in a HTTP GET request:

http://localhost/api/test?groceries=<the_above_raw_parameter_without_whitespaces>

Examples for parsing the JSON:

The value is a JSON String, and to parse it, use

get do    
  JSON.parse (params['groceries']['groceries_key'])
end

which will give you a nice json:

{
  "fruits": {
    "apples": 2
  },
  "vegetables": {
    "carrets": "a few"
  }
}

versions used:

gem 'grape',         '0.14.0'
gem 'grape-swagger', '0.20.2'
ruby 1.9.3p545
Yair Segal
  • 108
  • 1
  • 7