Generate request with raw post json, headers and additional parameters - ruby-on-rails

What I need:
send a POST request in an rspec test
with raw json data
a specific header
beside that I need two more params in my action that are usually generated from the URI by routing.
Any suggestions?
I know that I can use
post :action, 'raw data', 'CONTENT_TYPE' => 'application/json', 'custom-header' => 'value'
But how do I add that two params?
UPDATE:
I can send the request I need with curl this way:
curl -v -H "Content-Type: application/json" -H 'custom-header: value' -X POST -d #data.txt http://url.of.my.app
Here #data.txt is a file with a raw data. And the parameters I've mentioned in the last bullet are taken from url

you can pass custom things in a third parameter.
post :action, { your: json }, { content_type: 'application/json', custom_header: 'my_header }
http://api.rubyonrails.org/classes/ActionDispatch/Integration/RequestHelpers.html#method-i-get

Related

Ruby on Rails: How to Permit parameters with "_json"

I am trying to get POST requests to work coming from a React.js application to a Ruby on Rails API.
The parameters are:
Parameters: {"_json"=>"{'Name': 'ExampleSurvey', 'Draft_Status': 'true', 'Active_Status': 'false' }", "survey"=>{}}
My survey_params method is:
def survey_params
params.permit(:Name, :Draft_Status, :Active_Status)
end
My API Call from React is:
const post = (endpoint, body) => {
const url = ANAMNESIS_CONFIG.backend.location + endpoint ?? '';
return fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Anamnesis-Secret': ANAMNESIS_CONFIG.backend.secret
},
body: JSON.stringify(body)
}).then(response => response.json())
};
const submitHandler = e => {
e.preventDefault();
console.log({ surveyDetails })
post('survey',`{'Name': '${surveyDetails.name}', 'Draft_Status': 'true', 'Active_Status': 'false' }`)
}
The following Curl Request allows me to enter new surveys without any issues:
curl -X POST -d "Name=Example&Draft_Status=true&Active_Status=false" http://localhost:3000/survey
How can I edit Rails or React to get the Post request to work properly in a way that allows the curl request to still work?
Update:
Here is a picture from the logs: The first request is from Curl. The second request is from React. Hope this helps make the error more clear. Thanks for the help so far.
[
Changed the POST body from a string to a JSON object. This caused Rails to accept the params.
post('survey',{Name: surveyDetails.name, Draft_Status: true, Active_Status: false})
Shoutout to max (https://stackoverflow.com/users/544825/max) for coming up with solution!
In your controller you might want to skip forgery protection for json requests. It would be useful if you'd share a part of your logs where POST from React happens, otherwise it's hard to tell what the reason could be. This works when you get Can't verify CSRF token authenticity for your POST requests.
class ApplicationController < ActionController::Base
protect_from_forgery unless: -> { request.format.json? }
end

Rails JSON API testing POST request with PARAMS in JSON

This is a problem that has been bothering me for some time. I am building an API function that should receive data in json and response in json. My controller tests run fine(Since I abstract that the data gets there already decode from JSON and only the answer needs to be interpreted ).
I Also know that the function runs fine since I have used curl to test it with JSON arguments and it works perfectly.
(ex: curl -i --header "Accept: application/json" --header "Content-Type: application/json" -d '{"test":{"email":"andreo#benjamin.dk"}}' )
But obviously I would like to write request(feature) tests to test this automatically and the way I see it they should work exactly like curl, i.e., hit my service like it was an external call. That means that I would like to pass the arguments in JSON and receive an answer. I am pretty lost since all the examples I can see people treat arguments as it was already decoded.
My question is: I am following a wrong premise in wanting to send the arguments and request as a JSON one since i will be testing that rails works, because this is its responsibility? But I would like to see how robust my code his to wrong arguments and would like to try with JSON.
something of this type:
it "should return an error if there is no correct email" do
params = {:subscription => {:email => "andre"}}
post "/magazine_subscriptions", { 'HTTP_ACCEPT' => "application/json", 'Content-Type' => 'application/json', 'RAW_POST_DATA' => params.to_json }
end
Do you know how this is possible? and please let me know if you think I am testing it wrong.
all the best,
Andre
I found my answer on a post here(RSpec request test merges hashes in array in POST JSON params), I think what I was doing wrong concerned the arguments to the request.
so this worked:
it "should return an error if there is no correct email" do
params = {:subscription => {:email => "andre"}}
post "/magazine_subscriptions", params.to_json, {'ACCEPT' => "application/json", 'CONTENT_TYPE' => 'application/json'}
end
describe '#create' do
let(:email) {'andre'}
let(:attrs) {{email: email}}
let(:params) {{format: :json, subscription: attrs}}
it "should return an error if there is no correct email" do
post "/magazine_subscriptions", params
end
end

How can I post xml data using net/http that also has data in the url

I am working with an api that requires me to post xml to url such as someapi.com?userID=123. Thus far, I have tried this (assume the xml is composed already in the xml variable):
url = URI.parse('http://www.someapi.com/process_leads.asp')
request = Net::HTTP::Post.new(url.path)
request.content_type = 'text/xml'
request.body = xml
request.set_form_data({'userID' => '1204'}, ';')
response = Net::HTTP.start(url.host, url.port) {|http| http.request(request)}
I am trying to figure out if I can have the userID as form data but also post xml? I am basically supposed to post the xml to http://www.someapi.com/process_leads.asp?userID=1204. Is that possible?
I would consider using a Http library, e.g. HTTParty
Example using HTTParty for your request would look something like:
HTTParty.post('http://www.someapi.com/process_leads.asp', :query => {:userID => 1024}, :body => xml )
the :query option takes a hash of key/values which will be added to the post URL,
the :body is where the xml goes.
NOTE: some api's require the xml to have a name e.g. you may have to do something like
:body => "request=#{xml}"
Hope this helps.

Ruby on Rails: Functional Testing: POST does not send raw XML data

I have the following:
#request.env['RAW_POST_DATA'] = data
#request.env['CONTENT_TYPE'] = 'application/xml'
#request.env['HTTP_CONTENT_TYPE'] = 'application/xml'
post "create", :api_key => api_key, :format => "xml"
and test.log shows this:
Processing ****Controller#create to xml (for 0.0.0.0 at 2011-07-08 15:40:20) [POST]
Parameters: {"format"=>"xml", "action"=>"create", "api_key"=>"the_hatter_wants_to_have_tea1", "controller"=>"****"}
Which... I guess is fine, but the RAW_POST_DATA doesn't show up as a hash in the parameters list in the log.... now... it works when I call the action from the terminal using curl:
curl -H 'Content-Type: application/xml' -d '<object><name>Das Object</name></object>' http://notAvailableDuringTesting.butWorksInDevelopmentMode.dev/object.xml?api_key=the_hatter_wants_to_have_tea1
what am I doing wrong here?
Is there a reason why you aren't just passing the params to the post call itself? eg:
post "create", :api_key => api_key, :format => "xml", :params => data
Controller tests are there to test that the controller action does what it expects when you send it params that you already know of. they generally aren't there to test parsing of xml into params.
If you just want to test the former - then don't bother making them into xml - just pass them as a hash.
If you really do want to test parsing of xml into params - you may need to look into something that operates outside of the scope of rails tests (eg selenium or watir)

How to post JSON data in rails 3 functional test

I plan to use JSON data in both request and response in my project and having some problems in testing.
After searching for a while, I find the following code which uses curl to post JSON data:
curl -H "Content-Type:application/json" -H "Accept:application/json" \
-d '{ "foo" : "bar" }' localhost:3000/api/new
In the controller I can access the JSON data simply using params[:foo] which is really easy. But for functional testing, I only find post and xhr (alias for xml_http_request).
How can I write functional test in rails to achieve the same effect as using curl? Or should I do test in other ways?
Here's what I've tried. I find the implementation for xhr in action_controller/test_case.rb, and tried to add jhr method simply changing 'Conetent-Type' and 'HTTP_ACCEPT'. (Added in test/test_helpers.rb.)
def json_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
#request.env['Content-Type'] = 'Application/json'
#request.env['HTTP_ACCEPT'] ||= [Mime::JSON, Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
__send__(request_method, action, parameters, session, flash).tap do
#request.env.delete 'Content-Type'
#request.env.delete 'HTTP_ACCEPT'
end
end
alias jhr :json_http_request
I used this in the same way as xhr, but it does not work. I inspected the #response object and sees the body is " ".
I also find one similar question on Stack Overflow but it's for rails 2 and the answer for posting raw data does not work in rails 3.
As of Rails 5, the way to do this is:
post new_widget_url, as: :json, params: { foo: "bar" }
This will also set the Content-type header correctly (to application/json).
I found that this does exactly what I want – post JSON to a controller's action.
post :create, {:format => 'json', :user => { :email => "test#test.com", :password => "foobar"}}
Just specify appropriate content type:
post :index, '{"foo":"bar", "bool":true}', "CONTENT_TYPE" => 'application/json'
Json data should go as a string, not as a Hash.
Looking at stack trace running a test you can acquire more control on request preparation:
ActionDispatch::Integration::RequestHelpers.post => ActionDispatch::Integration::Session.process =>
Rack::Test::Session.env_for
Specifying :format does not work because request go as 'application/x-www-form-urlencoded' and json isn't parsed properly processing a request body.
Assuming you have a controller named api, a method named new, and you're in the test for the api controller:
#request.env["RAW_POST_DATA"] = '{ "foo" : "bar" }'
post :new
did the trick for me.
Here is a snippet that let me post json data to test my own app. rails 3
port = Rails.env.production? ? 80 : 3000
uri = URI.parse( Rails.application.routes.url_helpers.books_url(:host => request.host, :port => port, :format => :json) )
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.content_type = 'application/json'
request.body = #json_data
response = http.request( request )
#result = response.body
Hope this helps others
As #taro suggests in a comment above, the syntax that works for me in functional and integration tests is:
post :create, {param1: 'value1', param2: 'value2', format: 'json'}
(The curly braces aren't always necessary, but sometimes it doesn't work if they're missing, so I always add them.)
Here's what params and request.format look like for a post of that sort:
params:
{"param1"=>"value1", "param2"=>"value2", "format"=>"json", "controller"=>"things", "action"=>"create"}
request.format:
application/json
The best answer I can come up with to this is you don't
Whether or not it was intentional it s maybe good that rails doesn't implement this for you.
In functional tests you really want to just test your controller and not rails method of deserialization or even that routing and mime detection are all setup correctly, those all fall under an IntegrationTest.
So for your controllers, don't pass JSON just pass your params hash like you normally would. Maybe adding :format as an argument as well if you need to check that and respond differently.
If you want to test the full stack move to an IntegrationTest

Resources