Passing metadata with payload for Google Drive Rest API - ruby

I have been facing an issue in passing metadata with the Payload using the google drive api
I have been trying the following but title, description, etc is not applied to the uploaded file on drive.
upload_url = "https://www.googleapis.com/upload/drive/v2/files"
access_token = "---secret_access_token---"
fileitem = File.open('<filename>.pptx')
fileinfo = {"title": "insertedFromApi.pptx", "description": "Test description of file being uploaded from the API"}
params = {convert: true}
response = RestClient::Request.execute(
:method => :post,
:url => upload_url,
:headers => {"params": params, "uploadType": "multipart", content_type: 'multipart/related', accept: 'application/json', 'Authorization': "Bearer " + access_token},
:payload => {:content => fileitem, metadata: {title: 'insertedfromapi.pptx'}}
)
Although the google api says they accept metadata in multipart requests only, I have been doing that still all the files pushed are UNTITLED
Example request given here :-
POST /upload/drive/v2/files?uploadType=multipart HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Type: multipart/related; boundary="foo_bar_baz"
Content-Length: number_of_bytes_in_entire_request_body
--foo_bar_baz
Content-Type: application/json; charset=UTF-8
{
"title": "My File"
}
--foo_bar_baz
Content-Type: image/jpeg
JPEG data
--foo_bar_baz--

Related

How to Wrap guzzle json post body in array

I am having difficulty with an API and guzzle. The API requires a json content type, and basic auth. The api example request is
POST /endpoint/v1/create?id=1
[
{
"Name": "Test Room"
}
]
My Code:
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Middleware;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7;
$client = new Client(['base_uri' => env('base_uri')]);
$headers = [
'Authorization' => 'Basic',
'Accept' => 'application/json',
'Content-Type' => 'application/json',
];
$uri='/endpoint/v1/create?id=' . env('id');
$payload = ['Name' => 'Test Name'];
$response = $this->client->request('POST', $uri, ['auth' => ['username', 'password'], 'headers' => $headers, 'json' => $payload]);
All seems good to me. I've used guzzle this way in the past. However, The server responds with a "No data was submitted" Message.
The request:
POST /endpoint/v1/create?id=1 HTTP/1.1
User-Agent: GuzzleHttp/6.3.3 curl/7.58.0 PHP/7.2.5-1+ubuntu18.04.1+deb.sury.org+1
Authorization: Basic {Auth basic string goes here}
Host: {host goes here}
Accept: application/json
Content-Type: application/json
{"Name":"Test Name"}
The Response:
HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
WWW-Authenticate: Basic
Date: Thu, 21 Mar 2019 01:04:21 GMT
Content-Length: 36
{"Message":"No data was submitted."}
EDIT:
I'm able to successfully complete this request in postman. The API responds to [{"Name":"Test Name"}] but not {"Name":"Test Name"}, does anyone know how to replicate that with guzzle?
I was able to solve this problem by wrapping the payload in an array like so:
$payload = [['Name' => 'Test Name']];

Header parameter missing when making POST request using Rest-Client Ruby Gem

Hi I am successfully able to post from Post man , but unable to do so from Ruby Rest client.
Post details
Post Man Request
POST /endpoint HTTP/1.1
Host: host:11400
Accept: application/json
HTTP_USER: userid
fname: fname
lname: lname
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 589a5345-e384-bd71-d690-60987165487b
{ "rtdt":"09/08/2016","jobs":[{"pid":53} , {"pid":54}]}
the rest code I ve tried multiple ways including below
method tried
p RestClient.post 'http://url_details',
Accept: 'application/json',
'HTTP_USER'.to_sym => 'userid',
fname: 'name',
lname: '',
'Content-Type'.to_sym => 'application/json',
payload: JSON.parse('{ "rtdt":"09/08/2016","jobs":[{"pid":53} , {"pid":54}]}')
method tried
p RestClient.post 'http://url_details/job', http_user: 'userid', content_type: :json, accept: :json
method tried
p #uber_ride = (RestClient::Request.execute(
:method => :post,
:url => 'http://url_details/job',
'HTTP_USER' => 'userid',
:headers => {:content_type => 'application/json', :accept => 'application/json', :HTTP_USER => 'userid', :fname => 'name', :lname => 'lname'}
))
method tried
p '++++++++++++++++++++++++++++++++'
p RestClient.post($Current_Api_Endpoint,
$Current_Payload,
:http_user =>'userid',
headers:
{:accept => 'application/json',
:content_type => 'application/json',
:http_user =>'userid',
:fname => 'name',
:lname => 'lname'}
)
p '++++++++++++++++++++++++++++++++'
method tried
p env1 = ENV['http_proxy']
# p a = {:method => :post, :url => 'http://url_details/job', :headers => { :accept => 'application/json', :content_type => 'application/json', :http_user => 'userid', :fname => 'name', :lname => 'lname' }, :payload => { :rtdt => "06/10/2016",:jobs => [{:pid => 53} , {:pid => 54}]} }
p a = {
method: 'post',
url: 'http://url_details/job',
proxy: ENV['http_proxy'],
headers: {accept: 'application/json', content_type: 'application/json', http_user: 'userid', fname: 'name', lname: 'lname'},
payload: { rtdt: '06/10/2016', jobs: {pid: 53}}
}
I am getting error
HTTP Status 500 - HTTP_USER header not found in request
torg.springframework.security.web.authentication
I Found out the issue since then. All headers are able to be sent, except this one - This one in CAPS. rest of them in small characters. How to solve it
Ruby's Net::HTTP implementation does not transmit ALL_CAPS_UNDERSCORED header names. RestClient relies on Net::HTTP. So, for example, the HTTP_USER header is actually transformed into Http_user when transmitted.
Alertnative: curb
Curl, however, does not have this limitation. It transmits header names verbatim. Therefore instead of using RestClient, you could use the curb gem, which is a wrapper around libcurl. This seems to work:
require "curb"
Curl::Easy.http_post("http://URL_REDACTED") do |http|
http.headers["Accept"] = "application/json"
http.headers["Content-Type"] = "application/json"
http.headers["HTTP_USER"] = "userid"
http.post_body = '{ "rtdt":"09/08/2016","jobs":[{"pid":53} , {"pid":54}]}'
end
Alternative: excon
The excon gem is another possibility. It implements HTTP in pure Ruby, without relying on Net::HTTP. It does its own header processing and allows ALL_CAPS headers. So this should work:
require "excon"
Excon.post(
"http://URL_REDACTED",
:headers => {
"Accept" => "application/json",
"Content-Type" => "application/json",
"HTTP_USER" => "userid"
},
:body => '{ "rtdt":"09/08/2016","jobs":[{"pid":53} , {"pid":54}]}'
)
Anyway, I would argue that the server you are trying to connect to is ultimately at fault here, because headers are supposed to be evaluated as case-insensitive: Are HTTP headers case-sensitive?. If the server requires a header be in all uppercase, that is a bug.
The RestClient README examples indicate that the correct usage is:
RestClient.post(url, payload, headers)
So all you have to do is:
RestClient.post(
"http://URL_REDACTED",
'{ "rtdt":"09/08/2016","jobs":[{"pid":53} , {"pid":54}]}',
content_type: :json,
accept: :json,
"HTTP_USER" => "userid"
)
I tested against http://requestb.in and got the expected headers and body:
HEADERS
Total-Route-Time: 0
Connection: close
Via: 1.1 vegur
Connect-Time: 0
Http-User: userid
Content-Type: application/json
Content-Length: 55
User-Agent: rest-client/2.0.0 (darwin15.4.0 x86_64) ruby/2.3.1p112
X-Request-Id: c7cd819f-8901-41b9-8cbb-3b6d1895cd67
Accept-Encoding: gzip
Host: requestb.in
Accept: application/json
RAW BODY
{ "rtdt":"09/08/2016","jobs":[{"pid":53} , {"pid":54}]}

How to set Content-Length and Content-Type headers when sending a file with a HTTParty POST?

I'm setting the headers like this:
where file is a test.txt
size = File.size(file)
h = {
"Content-Type": 'text/plain'
"Content-Length": size.to_s,
"Other-Header": 'some-header'
}
b = File.read(file)
HTTParty.post('/some/api/url', {headers: h , body: b})
The request headers get set like this:
<- "POST /some/api/url\r\n
Content-Type: text/plain\r\n
Content-Length: 16\r\n
Other-Header: some-header\r\n
Connection: close\r\n
Host: somehost.com\r\n
Content-Length: 16\r\n
Content-Type: application/x-www-form-urlencoded\r\n\r\n"
Content-Length and Content-Type are added and duplicated, besides Transfer-Encoding gets set to chunked.
How can one set Content-Length, Content-Type and Transfer-Encoding and avoid HTTParty setting them on its own?
Hope it's clear.
Thx for your time!
Try this
HTTParty.post(END_POINT_URL,
:body => data.to_json,
:headers => { 'Content-Type' => 'application/json',
'Content-Length' => content_length, 'Other-Header' => other_header, } )

Uploading to Google Drive API using Ruby RestClient

I'm trying to upload a small image file to Google Drive using RestClient. I already have an access token (being requested in earlier code) but I am not sure how to form the payload.
The API docs state the request should look like this:
POST /upload/drive/v3/files?uploadType=media HTTP/1.1
Host: www.googleapis.com
Content-Type: image/jpeg
Content-Length: number_of_bytes_in_file
Authorization: Bearer your_auth_token
JPEG data
I have tried the following but it results in an error:
require 'rest-client'
file = File.open("./uploaded-by-api.jpg")
response = RestClient::Request.execute(method: :post, url: 'https://www.googleapis.com/upload/drive/v3/files', payload: { uploadType: "media", file: file, }, headers: { Authorization: "Bearer #{access_token}", "Content-Type" => "image/jpeg", "Content-Length" => "1000" })
I'm pretty sure there is a mistake in the way I'm including the actual file data but I can't find any examples of this with RestClient.
Ok solved it with the following:
response = RestClient.post(
'https://www.googleapis.com/upload/drive/v3/files',
{ 'uploadType' => "media", 'upload' => file },
"Authorization" => "Bearer #{access_token}",
"Content-Type" => "image/jpeg",
"Content-Length" => "1000"
)

OAuth gem not signing requests

I'm using the ruby gem for OAuth (http://oauth.rubyforge.org/) and I can't get it to create the authorization header for the provider I'm attempting to hit.
Here is my code:
consumer = OAuth::Consumer.new(auth[:consumer_key], auth[:consumer_secret], {
:site => 'http://api.rdio.com',
:scheme => :header
})
access_token = OAuth::AccessToken.new(consumer)
ap access_token.post('/1', :method => 'search', :query => 'Robert', :types => 'User')
When the requests happens, The header is not present in the call.
#<Net::HTTP::Post:0x7fbf149e91e0
#body_data = nil,
#header = {
"accept" => [
[0] "*/*"
],
"user-agent" => [
[0] "Ruby"
],
"content-length" => [
[0] "0"
],
"content-type" => [
[0] "application/x-www-form-urlencoded"
]
},
The header I'm referring to is the one that looks like this:
OAuth oauth_nonce=\"225579211881198842005988698334675835446\", oauth_signature_method=\"HMAC-SHA1\", oauth_token=\"token_411a7f\", oauth_timestamp=\"1199645624\", oauth_consumer_key=\"consumer_key_86cad9\", oauth_signature=\"1oO2izFav1GP4kEH2EskwXkCRFg%3D\", oauth_version=\"1.0\"
Looks like you are trying to do 2-legged oauth. See if this code works for you.
Edit: Updated Code Sample
gem 'oauth'
require 'oauth'
require 'net/http'
consumer = OAuth::Consumer.new('ENTER_KEY', 'ENTER_SECRET', {
:site => 'http://api.rdio.com',
:scheme => :header
})
resp = consumer.request(:post, '/1/search', nil, {}, 'method=search&query=Robert&types=User', { 'Content-Type' => 'application/x-www-form-urlencoded' })
puts resp.code + "\r\n"
puts resp.body
Edit: Added captured http stream
POST /1/search HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Accept: */*
User-Agent: OAuth gem v0.4.5
Content-Length: 37
Authorization: OAuth oauth_consumer_key="REDACTED_KEY", oauth_nonce="dwp8m2TGPHQNx3A7imLi7OkAULL7c0IWbTKefPXCsAY", oauth_signature="LxDZn6UNFLY%2FaXItu6MPK5a11js%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1330193449", oauth_version="1.0"
Connection: close
Host: api.rdio.com
method=search&query=Robert&types=UserHTTP/1.1 200 OK
X-Mashery-Responder: mashery-web1.LAX
Content-Type: application/json
Vary: Accept-Encoding
Vary: Accept-Language, Cookie
Content-Language: en
Cache-Control: no-cache
X-Version: 11.1
Accept-Ranges: bytes
Date: Sat, 25 Feb 2012 18:10:50 GMT
Server: Mashery Proxy
Content-Length: 2763
Connection: close
{"status": "ok", "result": {"person_count": 9603, "track_count": 93409, "number_results": 200, "playlist_count": 205, "results": ***TRUNCATED RESULTS FOR BREVITY***

Resources