Please help me understand, what i'm doing wrong?
I need to make POST request to api from my rails app, i tried to do it firstly with gem "faraday" and then with "net/http". Response from server the same. Account creates, but gives error:
Net::HTTPBadResponse (wrong header line format)
class Connect
require 'uri'
require 'net/http'
require 'net/https'
require 'faraday'
def initialize(email, password, account)
#base_url = "https://example.com"
#client_id = ENV["client_id"]
#client_secret = ENV["client_secret"]
#email = email
#password = password
#account = account
end
# method with net/http
def create_account
#toSend = {
first_name: #account[:first_name],
last_name: #account[:last_name],
client_id: #client_id,
client_secret: #client_secret,
email: #email,
password: #password
}.to_json
uri = URI.parse("#{#base_url}/endclient/api/account")
https = Net::HTTP.new(uri.host,uri.port)
https.use_ssl = true
req = Net::HTTP::Post.new(
uri.path,
initheader = {
'Content-Type' =>'application/json',
'Accept' =>'application/json'
}
)
req.body = "#{#toSend}"
res = https.request(req)
end
# faraday method
def make_account
conn = Faraday.new(:url => "#{#base_url}") do |faraday|
faraday.response :logger
faraday.adapter Faraday.default_adapter
end
params = { first_name: #account[:first_name],
last_name: #account[:last_name],
client_id: #client_id,
client_secret: #client_secret,
email: #email,
password: #password
}.to_json
response = conn.post do |req|
req.url '/endclient/api/account'
req.headers['Content-Type'] = 'application/json'
req.headers['Accept'] = 'application/json'
req.body = params
end
end
end
Done this request with success via Postman, so endpoint of the api is working.
Please help me understand what's wrong with headers ?
Thanks in advance!
UPDATE:
May be problem in this ?
Cannot render console with content type application/jsonAllowed content types: [#<Mime::Type:0x00000003661658 #synonyms=["application/xhtml+xml"], #symbol=:html, #string="text/html">, #<Mime::Type:0x00000003660fc8 #synonyms=[], #symbol=:text, #string="text/plain">, #<Mime::Type:0x0000000365ca68 #synonyms=[], #symbol=:url_encoded_form, #string="application/x-www-form-urlencoded">]
If you want a http lib that easily mixes into a class/module than I would recommend httparty over Faraday or just plain old Net::HTTP.
require 'httparty' # Requires go at the top of the file. Not in class body.
class MyApiClient
include HTTParty
base_uri 'test.example.com'
# Tells Httparty to send JSON for all requests.
format :json
# #see https://robots.thoughtbot.com/ruby-2-keyword-arguments
def initialize(client_id: ENV["client_id"], client_secret: ENV["client_secret"])
#options = {
body: {
client_id: client_id,
client_secret: client_secret
}
}
end
# #return [HTTParty::Response]
def create_account(first_name:, last_name:, email:, password:)
# ActiveSupport method that creates a copy so that we don't
# alter the instance options as a side effect.
opts = #options.deep_dup
opts[:body].merge!(
email: email,
password: password,
first_name: first_name,
last_name: last_name
)
self.class.post('/endclient/api/account', opts)
end
end
The nice thing is that httparty will do all the work with parsing the parameters to and from JSON and sending the correct headers. It also takes care of the dull work of building URI's.
Note that the method signature is slightly different:
client = MyApiClient.new
response = client.create_account(
first_name: 'John',
last_name: 'Doe',
email: 'john.doe#example.com',
password: 'abcd1234'
)
There was a problem on API side, wrong symbols in header.
Related
I don't understand what I do wrong. I want to send a simple request to an API, and it didn't work:
class Paytrace
require 'rest-client'
attr_reader :auth_token, :authorize
def initialize()
#auth_token = auth_token
end
def auth_token
response = RestClient.post 'https://api.paytrace.com/oauth/token', { grant_type: :password, username: "loginname", password: "htmlkoi8r" }
puts response
end
def authorize
headers = {:Authorization => "Bearer #{auth_token['access_token']}"}
response1 = RestClient.get('https://api.paytrace.com/v1/transactions/sale/keyed', headers)
puts response1
end
end
a = Paytrace.new
a.authorize
console.log
lucker#lucker-pc:~/git/paytrace-testh$ ruby integration.rb
{"access_token":"c6d69786f6075633:8647d6c6b6f6968327:092e8cfc553726d2b8198577ea2836f41173aae68a53aa1d2af2b2c7f65dcdc7","token_type":"Bearer","expires_in":7200,"created_at":1556098344}
{"access_token":"c6d69786f6075633:8647d6c6b6f6968327:232c92f977a301d033eec321c3d82b73bb65ebec33f9fcc8f6c2d7575c8b0d88","token_type":"Bearer","expires_in":7200,"created_at":1556098346}
Traceback (most recent call last): 1: from integration.rb:25:in
<main>' integration.rb:16:inauthorize': undefined method `[]' for
nil:NilClass (NoMethodError)
Why is the access_token generated twice?
Why is there an undefined method '[]' for nil:NilClass?
Your method auth_token is not returning a response, but a nil (puts returns nil).
Btw, you don't need attr_reader :authorize since you have a method with that name.
Also, as you are setting attr_reader :auth_token, the method auth_token must be rename (and maybe become private).
Change your code to:
class Paytrace
require 'rest-client'
attr_reader :auth_token
def initialize()
#auth_token = get_auth_token
end
def authorize
headers = {:Authorization => "Bearer #{auth_token['access_token']}"}
RestClient.get('https://api.paytrace.com/v1/transactions/sale/keyed', headers)
end
private
def get_auth_token
RestClient.post 'https://api.paytrace.com/oauth/token', { grant_type: :password, username: "loginname", password: "htmlkoi8r" }
end
end
a = Paytrace.new
puts a.auth_token
puts a.authorize
Seems like there are 3 mistakes in this code the 2 puts. line 12 and 20
and the
headers = {:Authorization => "Bearer #{auth_token['access_token']}"}
should be
headers = {:Authorization => "Bearer #{auth_token[:access_token]}"}
or
headers = {:Authorization => "Bearer #{#auth_token[:access_token]}"}
try this code
class Paytrace
require 'rest-client'
attr_reader :auth_token, :authorize
def initialize()
#auth_token = auth_token
end
def auth_token
response = RestClient.post 'https://api.paytrace.com/oauth/token', { grant_type: :password, username: "loginname", password: "htmlkoi8r" }
# puts response
end
def authorize
headers = {:Authorization => "Bearer #{#auth_token[:access_token]}"}
response1 = RestClient.get('https://api.paytrace.com/v1/transactions/sale/keyed', headers)
# puts response1
end
end
a = Paytrace.new
a.authorize
take care the your response hash if you check is
{:access_token=>"c6d69786f6075633:8647d6c6b6f6968327:092e8cfc553726d2b8198577ea2836f41173aae68a53aa1d2af2b2c7f65dcdc7",
:token_type=>"Bearer",
:expires_in=>7200,
:created_at=>1556098344}
and not
{"access_token":"c6d69786f6075633:8647d6c6b6f6968327:092e8cfc553726d2b8198577ea2836f41173aae68a53aa1d2af2b2c7f65dcdc7","token_type":"Bearer","expires_in":7200,"created_at":1556098344}
I am building a API to a recieve stats for a specific game.
Right now I am able to recieve stats once every time I start my server. After looking up 1 Player I and I'm trying to refresh the page to look up another(right now I am using gets.chomp via console to enter the names) I get the following error:
uninitialized constant SiteController::API
class SiteController < ApplicationController
require_relative '../../lib/api'
def stats
api = API.new(
username: 'someusername',
password: 'somepassword',
token: 'sometoken',
)
puts "Username: "
username = gets.chomp
puts "Platform: "
platform = gets.chomp
#allStats = api.getStats(username, platform)
end
end
api.rb
require 'net/http'
require 'json'
class API
def initialize(auth)
#auth = auth
#Token = getToken['access_token']
end
def TOKEN_URL
'https://antoherlink.com'
end
def EXCHANGE_URL
'https://somelink.com'
end
def LOOKUP_URL(username)
"https://somelink.com{username}"
end
def STATS_URL(id)
"https://somelink.com"
end
def httpGet(url, auth)
uri = URI(url)
req = Net::HTTP::Get.new(uri)
req['Authorization'] = auth
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(req)
end
JSON.parse(res.body)
end
def httpPost(url, params, auth)
uri = URI(url)
req = Net::HTTP::Post.new(uri)
req.set_form_data(params)
req['Authorization'] = auth
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(req)
end
JSON.parse(res.body)
end
def getToken
params = {
grant_type: 'password',
includePerms: true,
username: #auth[:username],
password: #auth[:password]
}
httpPost(TOKEN_URL(), params, "basic #{#auth[:token]}")
end
def getExchangeCode
httpGet(EXCHANGE_URL(), "bearer #{getToken['access_token']}")['code']
end
def getToken
params = {
grant_type: 'exchange_code',
includePerms: true,
token_type: 'eg1',
exchange_code: getExchangeCode
}
httpPost(TOKEN_URL(), params, "basic #{#auth[:anothertoken]}")
end
def lookup(username)
httpGet(LOOKUP_URL(username), "bearer #{#Token}")
end
def getRawStats(username)
httpGet(STATS_URL(lookup(username)['id']), "bearer #{#Token}")
end
def getStats(username, platform)
result = decodeRawStats(getRawStats(username), platform)
What did I miss?
Try changing:
class SiteController < ApplicationController
require_relative '../../lib/api'
# ...
end
to
require_dependency 'api'
class SiteController < ApplicationController
# ...
end
I am going to access the Riskscreen api to authenticate users. To test the api I have written a ruby code snippet to make sample POST call to get the number of tokens I have from the Riskscreen api.
My code is:
require 'uri'
require 'net/http'
require 'net/https'
require 'json'
#toSend = {}.to_json
uri = URI.parse("https://api.riskscreen.com/api/v1/user/tokens")
https = Net::HTTP.new(uri.host,uri.port)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
header = {'api-key': 'my api key','Content-Type': 'application/json', 'Accept': 'application/json'}
req = Net::HTTP::Post.new(uri.path, header)
req.body = "[ #{#toSend} ]"
res = https.request(req)
puts "------------"
puts "Response #{res.code} #{res.message}: #{res.body}"
But I am getting the following error:
Response 400 Bad Request
If I change the header line to
header = {'api-key'=> 'my-api-key','Content-Type'=> 'application/json', 'Accept'=> 'application/json'}
then I am getting this error:
Response 401 Unauthorized
Sticking with this for a while. Please help me to sort out this.
Header's keys must be String instead of Symbol
header = {'api-key' => 'my api key','Content-Type' => 'application/json', 'Accept' => 'application/json'}
Another issue is net/http is capitalize header automatically, api-key -> Api-Key which cause Authorization Error on your server. One solution is to create new class to wrap api-key to prevent Ruby do that
class HeaderCaseSensitive < String
def capitalize
self
end
def split(*args)
super.each do |str|
HeaderCaseSensitive.new(str)
end
end
def to_s
self
end
end
Then change header:
header = {HeaderCaseSensitive.new('api-key') => 'xxxx','Content-Type' => 'application/json', 'Accept' => 'application/json'}
To sum up, following code will work:
require 'uri'
require 'net/http'
require 'net/https'
require 'json'
class HeaderCaseSensitive < String
def capitalize
self
end
def split(*args)
super.each do |str|
HeaderCaseSensitive.new(str)
end
end
def to_s
self
end
end
#toSend = {}.to_json
uri = URI.parse("https://api.riskscreen.com/api/v1/user/tokens")
https = Net::HTTP.new(uri.host,uri.port)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
header = {HeaderCaseSensitive.new('api-key') => 'xxx','Content-Type' => 'application/json', 'Accept' => 'application/json'}
https.set_debug_output($stdout)
req = Net::HTTP::Post.new(uri.path, header)
req.body = "[ #{#toSend} ]"
res = https.request(req)
puts "------------"
puts "Response #{res.code} #{res.message}: #{res.body}"
Can you try remove:
req.body = "[ #{#toSend} ]"
and replace by:
req.set_form_data({})
# or
req.body = "{}"
Sorry, I'm not sure about that.
I am trying to set up the reset password emails for devise but my project uses amazon not the default mailer in ruby. How can i go about changing this?
Thanks!
UPDATE
I have connected the AmazonMailer using config.mailer = "AmazonMailer" now this is what my mailer looks like
class AmazonMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
default template_path: 'devise/mailer' # to make sure that your mailer uses the devise views
# require 'sendgrid-ruby'
# include SendGrid
# def send_email(subject, body, to_email, from_email)
# from = Email.new(email: "#{from_email}")
# to = Email.new(email: "#{to_email}")
# content = Content.new(type: 'text/html', value: "#{body}")
# mail = Mail.new(from, subject, to, content)
# personalization = Personalization.new
# personalization.to = to
# #personalization.custom_args = CustomArg.new(key: obj_type, value: obj_id)
# mail.personalizations = personalization
# puts mail.to_json
# sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'] || '[EXPOSED API KEY]', host: 'https://api.sendgrid.com')
# response = sg.client.mail._('send').post(request_body: mail.to_json)
# puts response.status_code
# puts response.body
# puts response.headers
# end
require 'aws-sdk'
require 'json'
# Overrides same inside Devise::Mailer
def reset_password_instructions(record, token, opts={})
end
def self.send_email(subject, body, from_name, from_email, to_email, source)
client = Aws::SES::Client.new
resp = client.send_email({
destination: {
bcc_addresses: [],
cc_addresses: [],
to_addresses: [to_email]
},
message: {
body: {
html: {
charset: "UTF-8",
data: body
},
text: {
charset: "UTF-8",
data: ""
}
},
subject: {
charset: "UTF-8",
data: subject
}
},
reply_to_addresses: [from_email],
#return_path: "",
#return_path_arn: "",
source: source,
#source_arn: ""
})
resp['message_id'] unless !resp && !resp['message_id']
end
end
inside my mailer I would like to override the reset_password_instructions method to send from Amazon and not the default.
I'm trying to do a request in httparty but it's not working
require 'httparty'
module PvWatch
class Client
include HTTParty
# base_uri ENV["pv_watch_endpoint"]
def login
response = self.class.post('http://pvwatch.xxx.xxx.xxx.net/api/v1/login', options)
end
def options
{
headers: {
'content-type' => 'application/json',
'access-key' => 'FORGET ABOUT THIS',
'authorization' => 'uri=api/v1/login'
},
body: {
username: "case",
password: "123"
}
}
end
end
end
the weird thing is that when i do the request with net/http is working and i don't know what i'm doing wrong with httparty
require 'uri'
require 'net/http'
module PvWatch
class Client
def login
url = URI("http://pvwatch.xxx.xxx.xxx.net/api/v1/login")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request["access-key"] = 'FORGET ABOUT THIS'
request["authorization"] = 'uri=api/v1/login'
request.body = "username=case&password=123"
response = http.request(request)
puts response.read_body
end
end
end
any idea what i'm doing wrong?