Cant set custom header params with rspec and Grape - ruby

I use Grape api and i need to write a test with custom header
my code:
it "should accept message" do
post "/api/v1/my/route", post_data, secret: "ASDFGHJKL"
last_response.status.should == 201
end
but the route gets no headers at all,
i also tried headers['secret'] = "ASDFGHJKL"
and also request.env['secret']
nothing works.
how can i pass headers in rspec to grape route?

Did you try header 'secret', 'ASDFGHJKL'?
More on the rack-test docs

Try using #request variable, e.g. #request.env['secret'] = 'ASDF..'. Hope this helps.
Also, take a look at this - Sending custom headers through RSpec

Related

Accept file upload (without a form) in Sinatra

I have this Sinatra::Base code:
class Crush < Sinatra::Base
post '/upload' do
erb params.inspect
end
end
I am using Postman and its interface for uploading a file. So I send a POST request with form-data, where in the body of the request the name is hello and the value is a file test.txt which contains just a simple string hey there.
When I do params.inspect I get this long string
{"------WebKitFormBoundaryocOEEr26iZGSe75n\r\nContent-Disposition: form-data; name"=>"\"hello\"; filename=\"test.txt\"\r\nContent-Type: text/plain\r\n\r\nhey there\r\n------WebKitFormBoundaryocOEEr26iZGSe75n--\r\n"}
So basically a long has with a single key and a single value. Reading most Sinatra tutorials (where the file is accepted from a form), there's a nice way Sinatra handles this using params[:file], but this doesn't seem to be the case when the file is coming straight from the body of an HTTP request.
I tried a non-modular approach too withou Sinatra::Base, thinking it's some parsing middle-ware missing, but got the same result.
Is there something I'm missing here? Must I go and make my own custom parser to get the content of this long hash? Or is there an easier way?
I figured it's Postman issue. When I switch from 'x-www-form-urlencoded' to 'form-data' in Postman, in the Header section, the field: Content-Type => application/x-www-form-urlencoded is NOT removed. So for those who encounter this problem, make sure you remove it manually.

Testing an AJAX POST using Rack::Test - how to pass in data?

I'm using Rack::Test to test my app and need to test the posting of data via AJAX.
My test looks like:
describe 'POST /user/' do
include Rack::Test::Methods
it 'must allow user registration with valid information' do
post '/user', {
username: 'test_reg',
password: 'test_pass',
email: 'test#testreg.co'
}.to_json, {"CONTENT_TYPE" => 'application/json', "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
last_response.must_be :ok?
last_response.body.must_match 'test_reg has been saved'
end
end
But at the server end it's not receiving the POSTed data.
I also tried just passing in the params hash without the to_json but that made no difference.
Any idea how to do this?
Your post endpoint must parse the posted JSON body itself, which I assume you already do. Can you post how your end point works, also the rack-test, rack,ruby and sinatra version numbers? Please mention also how you test whether the server's receiving anything -- namely test mockup may confuse your detection.
post '/user' do
json_data = JSON.parse(request.body.read.to_s)
# or # json_data = JSON.parse(request.env["rack.input"].read)
...
end
Okay so my solution is a little weird and specific to the way I am triggering my JSON request in the first place, namely using jQuery Validation and jQuery Forms plugins on the client end. jQuery Forms doesn't bundle the form fields into a stringified Hash as I'd expected, but sends the form fields via AJAX but as a classic URI encoded params string. So by changing my test to the following, it now works fine.
describe 'POST /user/' do
include Rack::Test::Methods
it 'must allow user registration with valid information' do
fields = {
username: 'test_reg',
password: 'test_pass',
email: 'test#testreg.co'
}
post '/user', fields, {"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
last_response.must_be :ok?
last_response.body.must_match 'test_reg has been saved'
end
end
Of course this is specific to the way the jQuery Forms plugin works and not at all how one would normally go about testing the POSTing of JSON data via AJAX. I hope this helps others.

How to read POST data in rack request

When I run the curl command
curl -v -H "Content-type: application/json" -X POST -d '{"name":"abc", "id":"12", "subject":"my subject"}' http://localhost:9292
to send a POST request with data to my Rack application, my code prints out {}. That is coming from puts req.POST() in the code below.
Why does it print out {} instead of the POST data? And how do I correctly access the POST data in my Rack application?
require 'json'
class Greeter
def call(env)
req = Rack::Request.new(env)
if req.post?
puts req.POST()
end
[200, {"Content-Type" => "application/json"}, [{x:"Hello World!"}.to_json]]
end
end
run Greeter.new
From reading the docs for POST, looks like it is giving you parsed data based on other content types. If you want to process "application/json", you probably need to
JSON.parse( req.body.read )
instead. To check this, try
puts req.body.read
where you currently have puts req.POST.
req.body is an I/O object, not a string. See the body documentation and view the source. You can see that this is in fact the same as mudasobwa's answer.
Note that other code in a Rack application may expect to read the same I/O, such as the param parsers in Sinatra or Rails. To ensure that they see the same data and not get an error, you may want to call req.body.rewind, possibly both before and after reading the request body in your code. However, if you are in such a situation, you might instead consider whether your framework has options to process JSON directly via some option on the controller or request content-type handler declaration etc - most likely there will be an option to handle this kind of request within the framework.
Try:
env['rack.input'].read
I found it in "How to receive a JSON object with Rack" and, though it still sounds weird to me, it likely works.
You can try:
req.params
Hope this can help you.

Sinatra, retrieve only post parameters

I know I can retrieve every parameter in Sinatra using "params".
However, How can I retrieve only post parameters? I need to verify that a parameter was sent by POST, otherwise it should be ignored.
Thanks.
Accessing the request object directly gives you a simple way of accessing post data, much like the php $_POST variable:
post '/' do
request.POST.inspect # instead of params.inspect
end
More info on the Rack request object here: http://rack.rubyforge.org/doc/classes/Rack/Request.html#M000274

is there a way to modify or send custom headers on grape?

I'm using Goliath and Grape. On my goliath server it calls the grape api like so:
when '/posts' then FrameworksAPI::API.call(env)
On my grape api class, my method is as simple as this:
get '/:id' do
Post.find(params[:id])
end
I'd like to modify the headers - specifically the 'Content-Length' but unsure how to.
Also i'd like to ask an additional question. How do i create callback/filters specifically before the method GET returns the result i'd like to modify the result.
Grape has a header helper for a few versions now.
header 'Content-Length`, 42.to_s
For your second question on modifying the body, try using after do ... at API level.
The return from your FrameworksAPI::API.call(env) method will be a triplet [status_code, headers, body]. So, instead of just returning that from your case you'd do something like:
when '/posts' then
status, headers, body = FrameworksAPI::API.call(env)
headers['whatever'] = blah
[status, headers, body]
You can also change the body, just be careful as the body maybe an array.
There is also a Content-Length middleware that is provided by Goliath. Content-Length is loaded by default although if you set a custom Content-Length it will take precedence. Just be carefull that other middlewares like the formattings don't change the body after you set your content-length.

Resources