How can i retrieve query params from get request - ruby

I'm kind of new to Ruby and I stuck with a fairly simple task.
I would like to pass GET parameters to Faraday's request.
Here is my request function
def request
#request ||= Faraday.new do |conn|
conn.url_prefix = BASE_URL
conn.headers = ##headers
conn.request :json
conn.response :json, parser_options: { object_class: OpenStruct }
end
Then this request method is being called like so
params = {"date_to": "2021.07.07", "date_from": "2022.01.30"}
request.get(url, params).body
I've tried to retrieve params in the request method using conn.params = #request.params
But that didn' work.

When you want to use params in the request method then you have to apss it to the method like this:
def request(params)
#request ||= Faraday.new do |conn|
conn.url_prefix = BASE_URL
conn.headers = ##headers
conn.params = params
conn.request :json
conn.response :json, parser_options: { object_class: OpenStruct }
end
And then call the methods like this:
params = { "date_to": "2021.07.07", "date_from": "2022.01.30" }
request(params).get(url).body

Related

Ruby base_auth with net/http - undefined method `user' for String

I've got pure Ruby app where I want to create request to external API. To do so I'm using standard Ruby Net::HTTP like below:
require 'net/http'
require 'uri'
class Api
BASE_URI = 'https://staging.test.com'
WORKFLOW = 'tests'
QUIZ_PATH = "/v3/accounts/workflows/#{WORKFLOW}/conversations"
def initialize(payload:)
#payload = payload
end
def post_quiz
handle_response(Net::HTTP.post_form("#{BASE_URI}#{QUIZ_PATH}", options))
end
attr_reader :payload
private
def options
{
basic_auth: basic_auth,
body: payload.to_json,
headers: headers
}
end
def basic_auth
{
username: Settings.ln_username,
password: Settings.ln_password
}
end
def headers
{
'User-Agent' => 'Mozilla/5.0',
'Accept-Language' => 'en-US,en;q=0.5',
'Content-Type' => 'application/json'
}
end
def handle_response(response)
return response.body if response.success?
end
end
But instead of response I'm getting an error:
NoMethodError: undefined method `user' for #String:0x00007f80eef9e6f8
Did you mean? super
/Users/usr/.rvm/rubies/ruby-2.7.0/lib/ruby/2.7.0/net/http.rb:527:in `post_form'
I don't have any user there, what is it?
Net::HTTP.post_form is used to send FormData pairs - its not what you want to send JSON and it doesn't even allow you to send headers (You're actually putting them in the request body!).
If you want to send a POST request with HTTP Basic auth and custom headers and JSON body you need to create the request object manually:
require 'net/http'
require 'uri'
class Api
BASE_URI = 'https://staging.test.com'
WORKFLOW = 'tests'
QUIZ_PATH = "/v3/accounts/workflows/#{WORKFLOW}/conversations"
attr_reader :payload
def initialize(payload:)
#payload = payload
end
def post_quiz
url = URI.join(BASE_URI, QUIZ_PATH)
request = Net::HTTP::Post.new(url, headers)
request.basic_auth = Settings.ln_username, Settings.ln_password
request.body = #payload.to_json
# open a connection to the server
response = Net::HTTP.start(url.hostname, url.port, use_ssl: true) do |http|
http.request(request)
end
handle_response(response)
end
private
def headers
{
'User-Agent' => 'Mozilla/5.0',
'Accept-Language' => 'en-US,en;q=0.5',
'Content-Type' => 'application/json'
}
end
# How to respond from an API client is a whole topic in itself but a tuple or hash might
# be a better choice as it lets consumers decide what to do with the response and handle stuff like logging
# errors
def handle_response(response)
# Net::HTTP doesn't have a success? method - you're confusing it with HTTParty
case response
when Net::HTTPSuccess, Net::HTTPCreated
response.body
else
false
end
end
end
Here is the source code that raises the error:
def HTTP.post_form(url, params)
req = Post.new(url)
req.form_data = params
>> req.basic_auth url.user, url.password if url.user
start(url.hostname, url.port,
:use_ssl => url.scheme == 'https' ) {|http|
http.request(req)
}
end
From the docs:
post_form(url, params)
Posts HTML form data to the specified URI object. The form data must be provided as a Hash mapping from String to String.
That means Net::HTTP.post_form(URI("#{BASE_URI}#{QUIZ_PATH}"), options) fixes it. You are currently sending a string as url instead of a URI.

How can I past a variable in request with HTTParty?

I need to generate a value using Post and pass this value in the query and delete. How to do this?
Is it possible to pass the value of a variable directly in the def retrieve method of request get or delete?
I want to use the same value generated in the var that stores the faker gem and pass both get and delete.
require 'HTTParty'
require 'httparty/request'
require 'httparty/response/headers'
class Crud
include HTTParty
def create
##codigo = Faker::Number.number(digits: 5)
#nome = Faker::Name.first_name
#salario = Faker::Number.decimal(l_digits: 4, r_digits: 2)
#idade = Faker::Number.number(digits: 2)
#base_url = 'http://dummy.restapiexample.com/api/v1/create'
#body = {
"id":##codigo,
"name":#nome,
"salary":#salario,
"age":#idade
}.to_json
#headers = {
"Accept": 'application/vnd.tasksmanager.v2',
'Content-Type': 'application/json'
}
##request = Crud.post(#base_url, body: #body, headers: #headers)
end
def retrieve
self.class.get('http://dummy.restapiexample.com/api/v1/employee/1')
end
end
Just parse response from API and use fetched id. You don't need to pass id when create an employee, it is generated automatically
class Crud
include HTTParty
base_uri 'http://dummy.restapiexample.com/api/v1'
def create
nome = Faker::Name.first_name
salario = Faker::Number.decimal(l_digits: 4, r_digits: 2)
idade = Faker::Number.number(digits: 2)
#note, you should pass body as JSON string
body = { name: nome, salary: salario, age: idade }.to_json
headers = {
'Accept' => 'application/vnd.tasksmanager.v2',
'Content-Type' => 'application/json'
}
self.class.post('/create', body: body, headers: headers)
end
def retrieve(id)
self.class.get("/employee/#{ id }")
end
end
> client = Crud.new
> response = client.create
> id = JSON.parse(response)['id']
> client.retrieve(id)
Please, read about variables in ruby - what is the difference between local, instance and global variables. Global variables should be used in rare case, more often you need instance/local ones.

Ruby HTTP sending API key Basic_auth

I have been following a tutorial on GitHub Pages and
I am trying to pass an Apikey to a webservice as basic auth 'apiKey' => 'huda7da97hre3rhr1yrh0130409u1u' for example but I cannot work out how to implement it into the method, or even if that is the proper place for it.
I have a class called connection with my request method in it. I need to post 'apiKey' as header and not in the body. I have read the ruby docs but I cannot work out how to apply it to this specific class.
require "net/http"
require "uri"
require "ostruct"
require "json"
class Connection
ENDPOINT = "http://localhost"
APP_LOCATION = "/task_manager/v1/"
VERB_MAP = {
:get => Net::HTTP::Get,
:post => Net::HTTP::Post,
:put => Net::HTTP::Put,
:delete => Net::HTTP::Delete
}
def initialize(endpoint = ENDPOINT)
uri = URI.parse(endpoint)
#http = Net::HTTP.new(uri.host, uri.port)
end
def get(path, params)
request_json :get, path, params
end
def post(path, params)
request_json :post, APP_LOCATION + path, params
end
def put(path, params)
request_json :put, path, params
end
def delete(path, params)
request_json :delete, path, params
end
private
def request_json(method, path, params)
response = request(method, path, params)
body = JSON.parse(response.body)
OpenStruct.new(:code => response.code, :body => body)
rescue JSON::ParserError
response
end
def request(method, path, params = {})
case method
when :get
full_path = encode_path_params(path, params)
request = VERB_MAP[method.to_sym].new(full_path)
else
request = VERB_MAP[method.to_sym].new(path)
request.set_form_data(params)
end
#http.request(request)
end
def encode_path_params(path, params)
encoded = URI.encode_www_form(params)
[path, encoded].join("?")
end
end
If I post to the server using Advanced Rest Client and put the apikey in the
http://localhost/task_manager/v1/tasks?=
header
Authorization: 9c62acdda8fe12507a435345bb9b2338
and in the body
email=free%40mail.com&password=free&task=test
then I get
{
error: false
message: "Task created successfully"
task_id: 5
}
So how can I post it using this class?.
connection = Connection.new
result = connection.post("task", {'task' => 'task'})
Basic Authentication example:
req = Net::HTTP::Get.new(uri)
req.basic_auth 'user', 'pass'
http://docs.ruby-lang.org/en/trunk/Net/HTTP.html#class-Net::HTTP-label-Basic+Authentication
Or if you want to add a raw Authorization header in your request method you can do
request.add_field 'Authorization', 'huda7da97hre3rhr1yrh0130409u1u'
But basic authentication normally means that there is a user name and a password. With your API key - I am not sure you actually need basic authentication. I do not know what you API actually requires but if you have not tried it yet you can try sending the api key as an additional parameter
result = connection.post("register", {'email' => email, 'name' => name, 'password' => password, 'apiKey' => 'huda7da97hre3rhr1yrh0130409u1u' })

how to use session in sinatra post request?

I am setting session in "/login" post request so when i trying to access that session in other api the session value will be nil.
post '/login', :provides => :json do
params = JSON.parse(request.env["rack.input"].read)
uname = params["username"]
session[:username] = random_string
return session[:username]
end
get '/list' do
puts session[:username]
end
"/list" call print "nil" in command line
What is the solution to use that session outside this post request once it set by "/login"?

Ruby mechanize post with header

I have page with js that post data via XMLHttpRequest and server side script check for this header, how to send this header?
agent = WWW::Mechanize.new { |a|
a.user_agent_alias = 'Mac Safari'
a.log = Logger.new('./site.log')
}
agent.post('http://site.com/board.php',
{
'act' => '_get_page',
"gid" => 1,
'order' => 0,
'page' => 2
}
) do |page|
p page
end
I found this post with a web search (two months later, I know) and just wanted to share another solution.
You can add custom headers without monkey patching Mechanize using a pre-connect hook:
agent = WWW::Mechanize.new
agent.pre_connect_hooks << lambda { |p|
p[:request]['X-Requested-With'] = 'XMLHttpRequest'
}
ajax_headers = { 'X-Requested-With' => 'XMLHttpRequest', 'Content-Type' => 'application/json; charset=utf-8', 'Accept' => 'application/json, text/javascript, */*'}
params = {'emailAddress' => 'me#my.com'}.to_json
response = agent.post( 'http://example.com/login', params, ajax_headers)
The above code works for me (Mechanize 1.0) as a way to make the server think the request is coming via AJAX, but as stated in other answers it depends what the server is looking for, it will be different for different frameworks/js library combos.
The best thing to do is use Firefox HTTPLiveHeaders plugin or HTTPScoop and look at the request headers sent by the browser and just try and replicate that.
Seems like earlier that lambda had one argument, but now it has two:
agent = Mechanize.new do |agent|
agent.pre_connect_hooks << lambda do |agent, request|
request["Accept-Language"] = "ru"
end
end
Take a look at the documentation.
You need to either monkey-patch or derive your own class from WWW::Mechanize to override the post method so that custom headers are passed through to the private method post_form.
For example,
class WWW::Mechanize
def post(url, query= {}, headers = {})
node = {}
# Create a fake form
class << node
def search(*args); []; end
end
node['method'] = 'POST'
node['enctype'] = 'application/x-www-form-urlencoded'
form = Form.new(node)
query.each { |k,v|
if v.is_a?(IO)
form.enctype = 'multipart/form-data'
ul = Form::FileUpload.new(k.to_s,::File.basename(v.path))
ul.file_data = v.read
form.file_uploads << ul
else
form.fields << Form::Field.new(k.to_s,v)
end
}
post_form(url, form, headers)
end
end
agent = WWW::Mechanize.new
agent.post(URL,POSTDATA,{'custom-header' => 'custom'}) do |page|
p page
end

Resources