Using Ruby server as API middleman - ruby

I am trying to call an API from my ruby server and simply pass the response back to my client.
How do I make sure the response is passed back to the client. I am currently getting back an empty response with a status code of 204
class SignupPlayerPagesController < ApplicationController
skip_before_action :authorize
def index
render locals: { signup_player_pages: SignupPlayerPage.all }
end
def show
signup_player_page = SignupPlayerPage.find_by(slug: params[:slug])
return render json: { error: 'Not found' }, status: :not_found if signup_player_page.nil?
render locals: { signup_player_page: signup_player_page }
end
def sms
response = HTTParty.get('http://api.stackexchange.com/2.2/questions?site=stackoverflow')
return response
end
end
The current HTTParty request is a dummy request I just want to know if it works.

which method is returning empty? index, show or sms?
if its sms, the you may need to do something like:
render json: { message: response }
instead of the "return response". Btw the "return response" can be deleted anyway, its redundant.

Related

how can i show user object data by passing user authentication_token in rails 5 restful json api?

in v1/controller
class V1::ProfilesController < ApplicationController
def index
if user = User.authentication_keys.present?
user = User.all
render json: {status: 'load', message:'load', user: 'user'},status: :ok
else
render json: {status: 'error', message:'error', user: 'user'},status: :ok
end
end
in routes
namespace :v1 do
resources :profiles
end
i am checking data in postman by passing authentication_token but it not show user object postman image]1
my user data in rails console
User id: 1, email: "adarsh1454#codekyt.com", created_at: "2018-11-14 07:35:59", updated_at: "2018-11-14 07:35:59", authentication_token: "tYHzjLm-6xxCeM4RXyEe"
You are passing 'user' as a string to your json. So it will just send that string.
You could try doing something like:
render json: {status: 'load', message:'load', user: user.to_json},status: :ok
Or even:
render json: user
That will get rid of the status and message json attributes, but you could argue the status should be shown by the HTTP response code and you shouldn't need the message if you are passing the user as the response.
edit
OK, from your comment I think you probably need something along the lines of:
def index
if request.headers["authentication_token"].present?
user = User.find_by(authentication_token: request.headers["authentication_token"])
render json: user
else
render json: { .... whatever you want to render if not authorised }
end
end
In successful case, you respond with the following json:
{status: 'load', message:'load'}
so everything is working as you described in controller. If you want to return user object, then change it to something like:
render json: { status: 'load', message:'load', user: 'user' }, status: :ok

Mocking a post request with binary data in Sinatra

I have an endpoint in my Sinatra application that will be receiving binary data as part of the body. The other application sending it data will have a Faraday request that looks like this:
connection = Faraday.new(url: "https://example.com/post_data") do |conn|
conn.request :multipart
conn.adapter :net_http
conn.headers['Content-Type'] = 'octet/stream'
end
#response ||= connection.post do |req|
req.params = { :host => host,
:verification => "false"}
req.body = my_base64_encoded_binary
end
Then, in Sinatra, I will have an endpoint that receives those request parameters and binary data and passes it along to a model, like so:
post '/post_data' do
request.body.rewind
payload = request.body.read
raise Sinatra::NotFound unless payload and params[:host]
output = MyOutput.new(params, payload)
content_type 'application/json'
body output.data
end
When I try to test this endpoint using Rack::Test helpers, I end up in a weird situation. I can't seem to create the proper mock in order to test this endpoint properly. Based on some manual testing with PostMan, I'm pretty certain my endpoint works properly. It's just the test that's holding me up. Here is the spec:
it "should return a json response" do
post(url, :host => host, :verification => "false") do |req|
req.body = [my_binary]
req.content_type = "application/octet-stream"
end
expect(last_response.status).to eq(200)
expect(last_response.content_type).to eq("application/json")
end
And when I inspect what the incoming request looks like in the test, it does not contain a proper body. params is properly set to the host and verification settings I set, but the body is also being set to the params (inspected through payload = request.body.read) instead of the binary.
Is there a different way to set up the mock so that the binary properly is set to the body of the request, and the parameters are still set to the request parameters properly?
The answer is that the only way to post the body is where I was adding the params in the rack test helper. I needed to take the params and move them into the query string of the URL in the request, and then only add the binary as the body of the post request in the test helper.
let(:url) { "http://example.com/post_data?host=>#{host}&verification=#{verification}" }
it "should return a json response" do
post(url, my_binary)
expect(last_response.status).to eq(200)
expect(last_response.content_type).to eq("application/json")
end

How to return a JSON response from a before block

I am writing a Sinatra-based API, and want to protect certain endpoints with an API key, validating the key before the route is processed.
I understand why throwing an error in the before block doesn't work, because the begin/rescue statements haven't been called yet, however I want a JSON response to be sent back to the client with the error message as a JSON object.
How would I do this?
namespace '/v1/sponser/:key' do
before do
if APIHelper.valid_key?(params[:key]) == false
throw 'Error, invalid API key'
# is it possible to return a JSON response from the before statement here?
end
end
get '/test' do
begin
json status: 200, body: 'just a test'
rescue => error
json status: 404, error: error
end
end
end
I would consider using halt:
before do
unless APIHelper.valid_key?(params[:key])
halt 404, { 'Content-Type' => 'application/json' },
{ error: 'Error, invalid API key' }.to_json
end
end
get '/test' do
json status: 200, body: 'just a test'
end
You can use halt method to return response with specific code, body and headers. So it looks like this:
before do
halt 401, {'Content-Type' => 'application/json'}, '{"Message": "..."}'
end
It looks sloppy so you can just redirect to another url, that provide some service

How can I return a response to an AngularJS $http POST to Sinatra?

I am able to successfully POST from AngularJS to my Sinatra route such that I get a "200" Status.
When I inspect in Chrome, I see the request payload as follows:
{"input":"testing"}
But response is empty.
Here is how I am POST-ing:
$http({
method: "POST",
url: "http://floating-beyond-3787.herokuapp.com/angular",
/*url: "https://worker-aws-us-east-1.iron.io/2/projects/542c8609827e3f0005000123/tasks/webhook?code_name=botweb&oauth=LOo5Nc0x0e2GJ838_nbKoheXqM0",*/
data: {input: $scope.newChat}
})
.success(function (data)
{
// $scope.chats.push(data);
$scope.chats.push($scope.newChat)
// if successful then get the value from the cache?
})
.error(function (data)
{
$scope.errors.push(data);
});
};
$scope.newChat = null
Chrome under Request Payload shows it properly -- as above.
When I check the logs in Heroku where I run my Sinatra app, I can't tell if I am properly processing the request payload. And I'm definitely not getting anything in the Response:
post '/angular' do
puts "params: #{params}"
puts params[:input]
puts #json = JSON.parse(request.body.read)
return RestClient.post 'https://worker.io' {:send => params[:input]}
end
My expectation is:
The Sinatra app can receive the payload :input
It can successfully post to my worker on iron.io
It can return something back in the Response to Angular JS along with Success.
Is this possible and if so, how?
Possibly you are running into a case where the request.body has already been read further up the chain before hitting your route.
Try the following
request.body.rewind
request_payload = JSON.parse request.body.read
This is a fairly common issue encountered in Sinatra so if this addresses your issue you may want to put it in a before filter.
before do
request.body.rewind
#request_payload = JSON.parse request.body.read
end
Also the following will not work with a JSON payload.
params[:input]
The params[:field] style works if the Content-Type is application/x-www-form-urlencoded to allow accessing form data in a traditional web application style. It also works to pull params off a parameterized route; something like the following.
post '/angular/:data'
puts params[:data]
# Do whatever processing you need in here
# assume you created a no_errors var to track problems with the
# post
if no_errors
body(json({key: val, key2: val2, keyetc: valetc}))
status 200
else
body(({oh_snap: "An error has occurred!"}).to_json) # json(hash) or hash.to_json should both work here.
status 400 # Replace with your appropriate 4XX error here...
end
end
Something I did recently was to use this last style post 'myroute/:myparam and then Base64 encode a JSON payload on the client side and send it in the URL :myparam slot. This is a bit of a hack and is not something I would recommend as a general practice. I had a client application that could not properly encode the JSON data + headers into the request body; so this was a viable workaround.

Output Raw HTTP Request without Sending in Ruby

I am trying to setup a POST request to a rest api using ruby. What I want to do is to output the raw HTTP request without actually sending the request. I have looked at HTTParty and Net:HTTP, but it seems the only way to output the request is only once you send the request. So basically I want a convenient way for creating an HTTP request string without actually having to send it.
The HTTParty.get and similar methods methods are helper functions that wraps a lot of the internal complexity; you should just peek inside the method to find that HTTParty.get to find that inside it it just makes a call to perform_request:
def get(path, options={}, &block)
perform_request Net::HTTP::Get, path, options, &block
end
and peeking into perform_request, we get that it just constructs a Request object and call perform on it:
def perform_request(http_method, path, options, &block) #:nodoc:
options = default_options.merge(options)
process_headers(options)
process_cookies(options)
Request.new(http_method, path, options).perform(&block)
end
You should take a look into the Request class.
Take a look at Typhoeus
request = Typhoeus::Request.new(
"www.example.com",
method: :post,
body: "this is a request body",
params: { field1: "a field" },
headers: { Accept: "text/html" }
)
It allows you to create the request and then you can run it or not with
request.run

Resources