How to get POST request from API with rails - ruby-on-rails

I got POST request from API. I checked content-type, it's x-www-form-urlencoded, but body request also contains JSON. How can I parse from JSON in hash?
Parameters of request in console: Screenshot || Parameters: {"vpbx_api_key"=>"etxojfklr6nue6tl627pn5sdi0koov7t", "sign"=>"ad0c49034c8d83a7d7f1b433afc2ed5a9aa08d933dba3724062aed0c3d1a79bb", "json"=>"{\"entry_id\":\"MjYyNjQ2NzM1Njo0Mg==\",\"call_id\":\"MToxMDAxNDAzOTo0Mjo4Mjc2NzEzMzk=\",\"timestamp\":1485939839,\"seq\":2,\"call_state\":\"Disconnected\",\"location\":\"abonent\",\"from\":{\"number\":\"79268220697\",\"taken_from_call_id\":\"MToxMDAxNDAzOTo0Mjo4Mjc2NzEwOTA6MQ==\"},\"to\":{\"extension\":\"2\",\"number\":\"79154612023\",\"line_number\":\"74953749768\"},\"disconnect_reason\":1100}"}

If you want to keep the form encoded that way, you will have the parameters in the params collection. That means you could be parsing that JSON doing something as:
def my_method_to_process_the_post
parsed = JSON.parse params[:json]
end
'json' is the key for the json that you are receiving in the payload.
For historical evolution of JSON parsing you may want to check this thread.

Related

Test the JSON response using rspec rails

I get all the responses from JSON in rails(API). How should I test the responses from JSON using rspec gem(CRUD operations)
Couple of ways.
You could validated it as a string.
You could parse JSON.parse(response) the response string, validate specific elements of the response.
Are something I can recommend.

Send an array of different hashes in a single POST HTTP request

I have two different kinds of hashes:
hash1 = {"h1_k1": "h1_v1", "h1_k2": ["h1_v2"]}
hash2 = {"h2_k1": "h2_v1", "h2_k2": "h2_v2"}
I may have numerous occurences of each hash with different values, but the following issue occurs even with a single occurence of each:
I want to send the data to a Rails server in an HTTP post request, and the behavior differs when I send it in a single request for the entire data and in one request per hash.
In the controller, params will be the following:
Single request: I push both hashes into an array and Net::HTTP.post_form(uri, array).
Parameters: {"{\"h1_k1\"=>\"h1_v1\", \"h1_k2"\"=>"=>{"\"h1_v2"\""=>{"}"=>nil}, {\"h2_k1\"=>\"h2_v1\", {\"h2_k2\"=>\"h2_v2\"}"=>nil}
One request per hash: array.each {|hash| Net::HTTP.post_form(uri, hash) }
Parameters: {"h1_k1": "h1_v1", "h1_k2": "h1_v2"} # array converted to string of only the last element
Parameters: {"h2_k1": "h2_v1", "h2_k2": "h2_v2"}
What is the reason behind this, and is there any way to properly send the data in a single request?
In the definition of post_form(url, params):
The form data must be provided as a Hash mapping from String to String
In your example, you have an Array that contains two hashes. Consider passing the params as Hash.
I ended up solving it in two different ways:
I used to_json on the array and I set the header Content-Type to be application/json.
This allowed instant access to the properly formatted array and hashes in the server side params[:_json].
For example params[:_json][0]['h1_k1'] gives h1_v1.
I used to_yaml on the array and I set the header Content-Type to any of the YAML options.
The params in the backend side were empty as (I guess) Rails couldn't parse it automatically, but using request.raw_post allowed to get the data from the post body.
Thus using Psych.safe_load(request.raw_post) parsed it back into an array of hashes, which allowed the use of the data just like in method 1 (disregarding params).

How to parse incoming JSON from my controller?

I am JSON posting the following JSON to my controller:
{"user_id": 234324, "user_action": 2, "updated_email": "asdf#asdf.com" }
In my controller I can see the JSON is correctly POSTED but I am not sure how to access it:
def update_email
puts request.body.read.html_safe
user_id = params[:user_id]
user = User.find(user_id)
end
I am testing this in my controller_spec and currently it is throwing an exception and is showing the id is empty.
This may be a duplicate - see: How do I parse JSON with Ruby on Rails?
I'm not sure how you're passing the JSON. Is it part of the POST params? In the header? Or something else. My guess is that you're either passing it as a param or should do so: e.g. myJson = {"user_id": 234324, "user_action": 2, "updated_email": "asdf#asdf.com" }
As far as parsing it goes, you should be able to use the built-in JSON class for this.
hash = JSON.parse params["myJson"]
Accessing it with params is the right way.
In your case:
params["user_id"] # => 234324
request.body.read shouldn't be used in real world, just for debugging, as action_dispatch does all the dispatch for you (like parse JSON or form data).
Note: you need to have the correct headers set, to let rails know that you're passing JSON.

Reading and Setting Rails Response Headers

I want to read the header of a request coming in to a Rails Controller...
How can I read in the header of the request to see what the request expects/wants back (in terms of formats) and send back data in that format?
example:
#in the controller receiving the request
def receive_req
request.head #read value from header
#if req wants json, format to json else, format to html etc...
res = response
res.head = "set appropriate header values"
res.body = "data to send back in the body"
end
#in the controller making the req
def send_request
Net::HTTP.post("/receive_req", "data", header_values)
render #{response.body}
end
Use the request.headers hash as described here.
Of course, you might also choose to define your routes in such a manner that each endpoint provides output in only one format. Whatever works for your application.

Rails impossible to get post response in rack middleware

I made a rails 3 rack middleware to log users actions with request = Rack::Request.new(env).
So i send to my database the request.fullpath and request.user_agent, as detailed below:
My issue appears I want to get the POST response too (to get ids, people name extracted from the JSON payload ...).
So i get the response = Rack::Response.new(request.path). But when i print response.body, i have only my request.path, and the request.params does not contain anything ...
By looking at the response with Firebug, I can see all the data I want.
Thanks for your responses.
Problem resolved !
I finally add status, headers, body = #app.call(env) to my middleware and send the body variable to my service. For each POST request, body contains all the post response I want.

Resources