In my Rails-api app I'am using Devise gem which when authenticating returns all crucial info (Access-Token, UID, Client etc) in Headers, like this:
Access-Token →DIbgreortZbCYKqzC8HdNg
Client →Y6J5oTIqS7Gc_-h9xynBQ
Uid →email2#example.com
I want those to be in the response Body. Is there any way to achieve this?
Rails provides you with a request object so you can grab whatever you need out of the headers in your controller.
def some_action
#mime_type = request.headers["Content-Type"] # => "text/plain"
#token = request.headers["key-for-your-token-here"]
end
You can then either pass it to your view or you can insert it into the response body via request.bodyas you would insert any key/value pair into a hash.
Documentation for ActionDispatch::Request found here:
http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-headers
UPDATE:
Make a custom method and see how long it has to run to navigate the header hash. If long you can use it to find the exact nesting of what you're looking for and change it.
def find_token(parent, request.headers)
request.headers.each {|key, value|
if value.is_a?(Hash)
find_token(key, value)
elsif key == 'THE TOKEN KEY HERE'
return value
else
next
end
}
end
Related
I have a method that will hit other API. And I made a condition to decide which auth token that will be used while posting to that API. Example:
class OrderFee
def perform
get_pricing
end
private
def get_pricing
payload = {
from: "a",
to: "b"
}
authorization = ''
if Config.UsingFirstToken?
authorization = "first_token"
else
authorization = "second_token"
end
response = Connection.MyCourier.post(url, payload) do |req|
req.headers['Authorization'] = authorization
end
response.body
end
end
I want to make 2 test case using Rspec to make sure if Config.UsingFirstToken true, it will hit the API using first_token, and otherwise. I can check the return value of this method, but I can't find a way to expect header from that POST action
You have access to the request object in your spec.
Expect what the header equals like this:
expect(request.headers['Authorization']).to eq("first_token")
Or whatever you expect the token to be.
I'm doing an API for my app.
Currently, you can call api/v1/clients and get the Clients JSON back, as expected. You can also do api/v1/clients?client_id=1 and get the JSON representation of the Client object with id 1.
Here's my API::V1::ClientsController:
class API::V1::ClientsController < ApplicationController
def index
if params[:client_id]
#client = Client.find(params[:client_id])
render template: 'api/v1/clients/show'
else
#clients = Client.all
end
end
end
I want that if, for example, you have a typo on the endpoint (api/v1/clients?clent_id=1), the app returns a JSON object with an error:
{
error: {
error_code: 10,
error_description: "Bad endpoint"
}
}
Is there a way to, say, make a switch statement on the params to handle the possible cases?
My suggestion:
Make a private method in your controller, this one will check your params:
If params is empty it returns false
If params contains 'client_id' and its value is a numeric it returns the value
Otherwise it raises an exception.
Then in you action method you use this result:
If the result is false you display all results
Otherwise it display the record based on the id returned by your private method
As for the exception: you use a rescue_from to display the "Bad endpoint" JSON response
I am using the following code in my MailChimp Controller to submit simple newsletter data. When It is sent I receive the following error as a "Method is not exported by this server -90" I have attached my controller code below. I am using this controller for a simple newsletter signup form. (Name, Email)
class MailchimpController < ApplicationController
require "net/http"
require "uri"
def subscribe
if request.post?
mailchimp = {}
mailchimp['apikey'] = 'f72328d1de9cc76092casdfsd425e467b6641-us2'
mailchimp['id'] = '8037342dd1874'
mailchimp['email_address'] = "email#gmail.com"
mailchimp['merge_vars[FNAME]'] = "FirstName"
mailchimp['output'] = 'json'
uri = URI.parse("http://us2.api.mailchimp.com/1.3/?method=listSubscribe")
response = Net::HTTP.post_form(uri, mailchimp)
mailchimp = ActiveSupport::JSON.decode(response.body)
if mailchimp['error']
render :text => mailchimp['error'] + "code:" + mailchimp['code'].to_s
elsif mailchimp == 'true'
render :text => 'ok'
else
render :text => 'error'
end
end
end
end
I highly recommend the Hominid gem: https://github.com/tatemae-consultancy/hominid
The problem is that Net::HTTP.post_form is not passing the "method" GET parameter. Not being a big ruby user, I'm not certain what the actual proper way to do that with Net::HTTP is, but this works:
require "net/http"
data="apikey=blahblahblah"
response = nil
Net::HTTP.start('us2.api.mailchimp.com', 80) {|http|
response = http.post('/1.3/?method=lists', data)
}
p response.body
That's the lists() method (for simplicity) and you'd have to build up (and urlencode your values!) your the full POST params rather than simply providing the hash.
Did you take a look at the many gems already available for ruby?
http://apidocs.mailchimp.com/downloads/#ruby
The bigger problem, and main reason I'm replying to this, is that your API Key is not obfuscated nearly well enough. Granted I'm used to working with them, but I was able to guess it very quickly. I would suggest immediately going and disabling that key in your account and then editing the post to actually have completely bogus data rather than anything close to the correct key. The list id on the other hand, doesn't matter at all.
You'll be able to use your hash if you convert it to json before passing it to Net::HTTP. The combined code would look something like:
mailchimp = {}
mailchimp['apikey'] = 'APIKEYAPIKEYAPIKEYAPIKEY'
mailchimp['id'] = '8037342dd1874'
mailchimp['email_address'] = "email#gmail.com"
mailchimp['merge_vars[FNAME]'] = "FirstName"
mailchimp['output'] = 'json'
response = nil
Net::HTTP.start('us2.api.mailchimp.com', 80) {|http|
response = http.post('/1.3/?method=listSubscribe', mailchimp.to_json)
}
I have a create action that handles XML requests. Rather than using the built in params hash, I use Nokogiri to validate the XML against an XML schema. If this validation passes, the raw XML is stored for later processing.
As far as I understand, the XML is parsed twice: First the Rails creates the params hash, then the Nokogiri parsing happens. I've been looking for ways to disable the params parsing to speed things up but have found nothing.
ActionController::Base.param_parsers[Mime::XML] = lambda do |body|
# something
end
I know it's possible to customize the XML params parsing in general using something like the above, but I depend on the default behaviour in other controllers.
Is it possible to bypass the params parsing on a per-action basis? What options do I have?
Thank you for your help!
I've managed to solve the problem using Rails Metal. The relevant part looks something like this:
class ReportMetal
def self.call(env)
if env["PATH_INFO"] =~ /^\/reports/
request = Rack::Request.new(env)
if request.post?
report = Report.new(:raw_xml => request.body.string)
if report.save # this triggers the nokogiri validation on raw_xml
return [201, { 'Content-Type' => 'application/xml' }, report.to_xml]
else
return [422, { 'Content-Type' => 'application/xml' }, report.errors.to_xml]
end
end
end
[404, { "Content-Type" => "text/html" }, "Not Found."]
ensure
ActiveRecord::Base.clear_active_connections!
end
end
Thanks!
PS: Naive benchmarking with Apache Bench in development shows 22.62 Requests per second for standard Rails vs. 57.60 Requests per second for the Metal version.
I'm using swfupload's most recent version, 2.2.0 and rails 2.3.3. Having seen a number of statements to the effect that I would have to replace CGI::Session.initialize with a chunk of code to extract the session from key-value pairs injected into my form url, I incorporated the code segment into my environment.rb:
require 'cgi'
class CGI::Session
alias original_initialize initialize
def initialize(request, option = {})
session_key = option['session_key'] || '_session_id'
query_string = if (qs = request.env_table["QUERY_STRING"]) and qs != ""
qs
elsif (ru = request.env_table["REQUEST_URI"][0..-1]).include?("?")
ru[(ru.index("?") + 1)..-1]
end
if query_string and query_string.include?(session_key)
option['session_id'] = query_string.scan(/#{session_key}=(.*?)(&.*?)*$/).flatten.first
end
original_initialize(request, option)
end
end
I do see the session info being correctly packed into the form parameters as files are uploaded, but the above code is never firing to bring the session info out of the database.
What's the secret sauce to get from params-packed session id and authenticity tokens (they're not being picked up from the params, either)?
Rack middleware to the rescue