How to Wrap guzzle json post body in array - laravel

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']];

Related

How to use Typhoeus::Request object using https

I'm trying to make an https request using the Typhoeus::Request object and i don't get it working.
The code i'm running is something like this:
url = "https://some.server.com/"
req_opts = {
:method => :get,
:headers => {
"Content-Type"=>"application/json",
"Accept"=>"application/json"
},
:params=>{},
:params_encoding=>nil,
:timeout=>0,
:ssl_verifypeer=>true,
:ssl_verifyhost=>2,
:sslcert=>nil,
:sslkey=>nil,
:verbose=>true
}
request = Typhoeus::Request.new(url, req_opts)
response = request.run
The response i'm getting is this:
HTTP/1.1 302 Found
Location: https://some.server.com:443/
Date: Sat, 27 Apr 2019 02:25:05 GMT
Content-Length: 5
Content-Type: text/plain; charset=utf-8
Why is this happening?
Well it's hard to know because your example is not a reachable url. But 2 things I see is that you are not passing an ssl cert or key. But also 302 indicates a redirect. You can try to follow redirection but your first problem is probably you don't need to set SSL options, why are you?
See if you try the following options:
req_opts = {
:method => :get,
:headers => {
"Content-Type"=>"application/json",
"Accept"=>"application/json"
},
:params=>{},
:params_encoding=>nil,
:timeout=>0,
:followlocation => true,
:ssl_verifypeer=>false,
:ssl_verifyhost=>0,
:verbose=>true
}
See the following sections for more info
https://github.com/typhoeus/typhoeus#following-redirections
https://github.com/typhoeus/typhoeus#ssl

Yii2 and reactjs CORS filters gives Error: Response for preflight has invalid HTTP status code 401

I am trying to use ajax request in reactJs to fetch a resource that require authentication from Bearer Auth in Yii2.
Request Headers
Accept: /
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: GET
Connection: keep-alive
Host: localhost
Origin: http://localhost:8110
Referer: http://localhost:8110/
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Response Headers
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Authorization
Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS
Access-Control-Allow-Origin: http://localhost:8110
Connection: Keep-Alive
Content-Length: 150
Content-Type: application/json; charset=UTF-8
Date: Fri, 21 Apr 2017 10:36:27 GMT
Keep-Alive: timeout=5, max=99
Server: Apache/2.4.25 (Ubuntu)
Www-Authenticate: Bearer realm="api"
This is my behavior method in yii2 framework
public function behaviors()
{
$behaviors = parent::behaviors();
unset($behaviors['authenticator']);
return [
[
'class' => 'yii\filters\ContentNegotiator',
'only' => ['view', 'index', 'filters', 'slug', 'shortlist'], // in a controller
// if in a module, use the following IDs for user actions
'formats' => [
'application/json' => Response::FORMAT_JSON,
],
],
'corsFilter' => [
'class' => \yii\filters\Cors::className(),
'cors' => [
'Origin' => ['*'],
'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'OPTIONS'],
'Access-Control-Request-Headers' => ['*'],
'Access-Control-Allow-Credentials' => true,
],
],
'authenticator' => [
'class' => \yii\filters\auth\HttpBearerAuth::className(),
'except' => ['options'],
],
];
}
I know this some issue related to CORS because the same request is working fine with Postman and cURL(from terminal) with the same token, reactjs and ajax showing the same error.
Your mistake is at:
'except' => ['options'],
Class "HttpBearerAuth" inherits yii\base\ActionFilter which public property "$except" according to the documentation defines a "list of action IDs that this filter should not apply to". Not the http methods.
So the above will not except a preflight request from "authenticator", but to the actionOptions() which is not what you want.
What you should do is avoid returning a 401 http error for an OPTIONS http request(which causes your error), and just return a 200 empty response.
You could do this by adding:
public function beforeAction($action)
{
//your code
if (Yii::$app->getRequest()->getMethod() === 'OPTIONS') {
parent::beforeAction($action);
Yii::$app->getResponse()->getHeaders()->set('Content-Type', 'text/plain');
Yii::$app->end();
}
return parent::beforeAction($action);
}

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, } )

Passing metadata with payload for Google Drive Rest API

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--

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