FCM API Bad Request - ruby-on-rails

I'm trying to push a notification through FCM from my Ruby on Rails project, here is my code:
require 'net/http'
require 'json'
def send_notifications
log = Logger.new("log/notifications.log")
begin
uri = URI.parse("https://fcm.googleapis.com/fcm/send")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
key = '...'
hash = {:notification => {:sound => "default", :title => "test", :text => "test", :badge => "0"}, :data => {:targetID => "1", :to => "..."}}
req = Net::HTTP::Post.new(uri.path, {'Content-Type' => 'application/json', 'Authorization' => "key=#{key}"})
req.body = hash.to_json
response = http.request(req)
log.debug("response #{response.body}")
rescue => e
log.debug("failed #{e}")
end
end
I'm getting Bad Request 400 error, and debugging the response body only shows this: "to"
Please help me debug this issue. Thank you

Related

How to make a proper POST request in Rails (while converting from Curl)?

I'm trying to convert a Curl request into my Rails app. It seems that the online converter that I'm using is kind of buggy.
The current state is:
require 'net/http'
require 'uri'
require 'json'
class Listing < ApplicationRecord
def getit2
uri = URI.parse("https://www.somedomain.com/api/public/v1.0/markers/list")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/json"
request["Origin"] = "https://www.somedomain.com"
request["Accept-Language"] = "en-US,en;q=0.9,ar;q=0.8,bg;q=0.7,de;q=0.6,es;q=0.5,fr;q=0.4,he;q=0.3,hu;q=0.2,it;q=0.1,ms;q=0.1,nl;q=0.1,nb;q=0.1,ru;q=0.1,sk;q=0.1,sv;q=0.1,tr;q=0.1,vi;q=0.1,zh-CN;q=0.1,zh;q=0.1"
request["User-Agent"] = "Mozilla/5.0 (Linux; Android 4.0; Nexus 5 Build/MRA58N) AppleWebKit/535.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Mobile Safari/537.36"
request["Accept"] = "application/json"
request["Referer"] = "https://www.google.co.uk"
request["Cookie"] = "_pxhd=2f7043c8ae569c7ddddd12207ac90cca0ef2a40d61378c41112492:46c5aca1-7401-11e9-ab6d-251d1e721a9f; _gcl_au=1.1.2102026563.1557588441; Infinite_lastSearch_key=; Infinite_user_id_key=7ba2e36f-2a47-46bf-a275-04d5b2cbe965; Infinite_ab_tests_context_key={%22context%22:{%22price_estimation%22:%22false%22%2C%22display_sold%22:%22false%22%2C%22display_sold_v2%22:%22true%22%2C%22price_estimation_v2%22:%22true%22%2C%22price_estimation_v3%22:%22false%22}%2C%22values%22:{%22price_estimation%22:%22false%22%2C%22display_sold%22:%22false%22%2C%22display_sold_v2%22:%22true%22%2C%22price_estimation_v2%22:%22true%22%2C%22price_estimation_v3%22:%22false%22}}; _pxvid=46c5aca1-7401-11e9-ab6d-251d1e721a9f; _ga=GA1.3.1522435888.1557588443; _gid=GA1.3.1336624029.1560436285; AWSELB=CD9FE1B30E32EDF52EB77EE30BE426CF7F363C127FE2A9BC2F70F9F1CDD10FF86A1B4095995C86A57A485BDD3A564FE18D63589FAE6A0457DFADBDFF864B86DAA86999D390; _sp_id.549d=457ec9d1-91b0-4e92-a50a-1d6517ccb887.1560168270.6.1560586655.1560522000.895c4b58-2ee1-45ca-bf34-b0e4716eac0d; _ud=0f90bb52e08b81cc0d5493b6de1c53b81d7a25c4-cid=116ea8bc-6bbd-4661-b5a6-f65725ec0e6d&_ts=1560595069960; _dc_gtm_UA-26019961-1=1; _px3=d331cc7dc802bed39645428247a9f83be0c89dc82d9c549bad4bc2bfe2823676:XUO7Topo8ACRMvx9jjEXR5qW+CpujeC0thydfP6jHjpGr4G0iPU2Qm4m5IDAn/Pk8qsHxJKaowm58pMULV9MIw==:1000:dqOcC/gfWU9y/hUxvT6akY2ZBKdd+M5HDrxR9UaggnszreSjIkckWJVscq59PjoRCAiNJhfIEGaHC++sor4DUOc4iwZRQgthPouxNYgqkeKCqjPXwOrsSBppi1Yh3L3AF+2Kv/msYsE+F7ol8ALbGQQp3LkYOa4ta1RIZeLhHTQ="
request["Connection"] = "keep-alive"
request.body = JSON.dump({
"sortBy" => "auto",
"areaId" => "the area",
"isStreetAreaId" => false,
"filters" => "{"dealTypes":["FOR_SALE"],"addBulletinFromPrivate":true,"addBulletinFromAgent":true,"addProjects":true,"propertyTypes":[],"conditions":[]}",
"zoom" => 11.366136034830756,
"NELat" => 1,
"NELng" => 1,
"SWLat" => 1,
"SWLng" => 1,
"slim" => true
})
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
end
end
And the console is raising this error:
/app/models/listing.rb:38: syntax error, unexpected tIDENTIFIER,
expecting '}'
"filters" => "{"dealTypes":["FOR_SALE"],"addBulletinFr...
^
It seems that it fails in the filters data point. How should it be structured to create a valide request?
Use a dedicated gem for that. HTTParty is a great example.
class MyAPI
include HTTParty
base_uri 'https://www.somedomain.com/api/public/v1.0'
headers 'Content-Type' => 'application/json', 'Accept' => 'application/json'
end
MyAPI.post(
'/markers/list', body: {
"sortBy" => "auto",
# ...
}.to_json
)
Of course, depending on the actual contents of the response, you will need to do some parsing, but HTTParty is able to parse automatically if the response Content-Type header is correctly set.

How to call JDoodle API from local Rails server?

I am calling the JDoodle API with post request from my local machine Rails server with valid id and secrete. I am not getting desired response. Please suggest me if i am doing wrong....
My Ruby function to make api call
def run_Jddodle_API
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse("https://api.jdoodle.com/v1/execute")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/json; charset=UTF-8"
request.body = {
"clientId" => "ddc371fd*************c8efbae",
"clientSecret" => "4ee8e79a225***************************a8ee7f331aeeca603",
"script" => "<?php printf(\"hello RAJA\"); ?>",
"language" => "php",
"versionIndex" => "0"
}.to_json
req_options = { use_ssl: uri.scheme == "https", }
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
puts response.body
end
And the response is
{"error":"Unauthorized Request","statusCode":401}
try changing this line:
request.content_type = "application/json; charset=UTF-8"
to this:
request.content_type = "application/json"
I changed the code as below and it worked but can't say why.?
require 'uri'
require 'net/http'
require 'net/https'
url = URI("https://api.jdoodle.com/v1/execute")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url.path)
request["Content-Type"] = 'application/json'
request.body = {
"script" => params[:code],
"language" => params[:lang],
"versionIndex" => params[:version],
"clientId" => "dc37******************efbae",
"clientSecret" => "4ee8e79a225a5525*******************************************"
}.to_json
response = http.request(request)
puts response.read_body`

Issue regarding http POST api call using ruby code

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.

Ruby POST with custom headers and body?

I'm trying to POST to Mailchimp in Ruby but I can't get any code working which has custom headers and a body. This is the request I am trying to replicate:
curl --request GET \
--url 'https://<dc>.api.mailchimp.com/3.0/' \
--user 'anystring:<your_apikey>'
but I also have to add a JSON body.
If I run this code:
postData = Net::HTTP.post_form(URI.parse('https://xxx.api.mailchimp.com/3.0/lists/xxx/members/'), { ... }})
puts postData.body
I get a response from Mailchimp that the apikey is missing. How do I add the API key?
Based on these posts:
Ruby request to https - "in `read_nonblock': Connection reset by peer (Errno::ECONNRESET)"
Ruby send JSON request
I tried this:
uri = URI('https://xxx.api.mailchimp.com/3.0/lists/xxxx/members/')
req = Net::HTTP::Post.new(uri, initheader = {'Content-Type' =>'application/json'})
req.basic_auth 'anystring', 'xxxx'
req.body = URI.encode_www_form({ ... }})
response = Net::HTTP.new(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https').start {|http| http.request(req) }
puts "Response #{response.code} #{response.message}:#{response.body}"
but I get the error TypeError (no implicit of Hash into String) on the response = ... line. What is the error referring to and how do I fix it?
UPDATE:
using start instead of new:
response = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https') {|http| http.request(req) }
I am able to send the request, but I get a 400 response: "We encountered an unspecified JSON parsing error"
I get the same response with the posted answer. here is my JSON:
{'email_address' => 'xxxx#gmail.com', 'status' => 'subscribed', 'merge_fields' => {'FNAME' => 'xxx', 'LNAME' => 'xxx' }
I also tried adding the data like this:
req.set_form_data('email_address' => 'xxxx#gmail.com', 'status' => 'subscribed', 'merge_fields' => {'FNAME' => 'xxx', 'LNAME' => 'xxx' } )
but I get the same JSON parse error
Try this, if it works for you
uri = URI('https://api.mailchimp.com/3.0/lists/xxxx/members/')
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = 'application/json'
req.basic_auth 'username', 'password'
req.set_form_data('from' => '2005-01-01', 'to' => '2005-03-31')
response = http.request req # Net::HTTPResponse object
end
You need to set form data in post request like
req.set_form_data('from' => '2005-01-01', 'to' => '2005-03-31')
Updates:
Try posting raw data like
json_data = {'from' => '2005-01-01', 'to' => '2005-03-31'}.to_json
req.body = json_data

no method on use_ssl = true

I'm trying to send post request using rails controller, however i faced issue, when i cant make controller accept use_ssl = true.
Here is my code
require "net/http"
require "uri"
params = {'requestId' => '1',
'merchantId' => 'merchantid'
'version' => '1.0.6',
'locale' => 'en_US',
'externalUserId' => '1234',
'partnerId' => 'partnerid',
'emailAddress' => 'test#email.com',
'deviceDTO' => "{'id' => '123123213', 'deviceType' => 'samsung'}",
'timestamp' => Time.now.strftime('%Y-%m-%dT%H:%M:%S.%L%z')
}
url = URI.parse('https://example.com')
http = Net::HTTP::Post.new(url.host)
http.set_form_data(params)
#http.use_ssl = true
#http.verify_mode = OpenSSL::SSL::VERIFY_PEER
res = Net::HTTP.start(url.hostname, url.port) do |h|
h.request(http)
h.use_ssl = true
h.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
errors are :
NoMethodError: undefined method `use_ssl=' for #<Net::HTTP::Post POST>
NoMethodError: undefined method `verify_mode=' for #<Net::HTTP::Post POST>
UPD
error now
Errno::ECONNRESET: Connection reset by peer
use_ssl is a method in Net::HTTP, you are creating a Net::HTTP::Post object.
You might want to do
url = URI.parse('https://example.com/')
http = Net::HTTP.new(url.host, url.port)
if url.scheme == 'https'
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
end
http.post(url.path, params)

Resources