Guzzle POST request always returns 400 Bad Request - laravel

I have been trying to make a simple POST request to an endpoint with a payload using Guzzle but I always get 400 Bad Request returned.
I can make the same request in Postman and it works. Also, If I make the request using cURL it works.
Can anyone tell from my code what I am doing wrong?
Here's the original cURL request:
curl "https://endpoint.com/" \
-H "Authorization: ApiKey pp_test_*********" \
--data '{
"shipping_address": {
"recipient_name": "Deon Botha",
"address_line_1": "Eastcastle House",
"address_line_2": "27-28 Eastcastle Street",
"city": "London",
"county_state": "Greater London",
"postcode": "W1W 8DH",
"country_code": "GBR"
},
"customer_email": "email£example.com",
"customer_phone": "123455677",
"customer_payment": {
"amount": 29.99,
"currency": "USD"
},
"jobs": [{
"assets": ["http://psps.s3.amazonaws.com/sdk_static/1.jpg"],
"template_id": "i6_case"
}, {
"assets": ["http://psps.s3.amazonaws.com/sdk_static/2.jpg"],
"template_id": "a1_poster"
}]
}'
And the Postman PHPHttp Request which works too.
<?php
$request = new HttpRequest();
$request->setUrl('https://endpoint.com/');
$request->setMethod(HTTP_METH_POST);
$request->setHeaders(array(
'cache-control' => 'no-cache',
'Connection' => 'keep-alive',
'Content-Length' => '678',
'Accept-Encoding' => 'gzip, deflate',
'Host' => 'api.kite.ly',
'Cache-Control' => 'no-cache',
'Accept' => '*/*',
'User-Agent' => 'PostmanRuntime/7.19.0',
'Content-Type' => 'text/plain',
'Authorization' => 'ApiKey pk_test_*******'
));
$request->setBody(' {
"shipping_address": {
"recipient_name": "Deon Botha",
"address_line_1": "Eastcastle House",
"address_line_2": "27-28 Eastcastle Street",
"city": "London",
"county_state": "Greater London",
"postcode": "W1W 8DH",
"country_code": "GBR"
},
"customer_email": "email#example.com",
"customer_phone": "12345667",
"customer_payment": {
"amount": 29.99,
"currency": "USD"
},
"jobs": [{
"assets": ["http://psps.s3.amazonaws.com/sdk_static/1.jpg"],
"template_id": "i6_case"
}, {
"assets": ["http://psps.s3.amazonaws.com/sdk_static/2.jpg"],
"template_id": "a1_poster"
}]
}');
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
But when I try to send make the same request with Guzzle it fails with 400 Bad Request and I can't understand why.
$data = [
"shipping_address" => [
"recipient_name" => "Deon Botha",
"address_line_1" => "Eastcastle House",
"address_line_2" => "27-28 Eastcastle Street",
"city" => "London",
"county_state" => "Greater London",
"postcode" => "W1W 8DH",
"country_code" => "GBR"
],
"customer_email" => "example#email.com",
"customer_phone" => "+44 (0)784297 1234",
"customer_payment" => [
"amount" => 29.99,
"currency" => "USD"
],
"jobs" =>
[
"assets" => ["http://psps.s3.amazonaws.com/sdk_static/1.jpg"],
"template_id" => "i6_case"
]
];
$options = json_encode($data);
$response = $client->request('POST', config('services.endpoint.com'),
['headers' => ["Authorization" => config('services.endpoint.com.public_key'),
'Content-Type' => "application/json"], $options]);
If anyone can help me to debug this I'd be really grateful.

If you're using Guzzle 6 (and you probably should be), you're actually constructing in a more complex way than you need to, such that the endpoint is not receiving the expected JSON. Try this instead:
$client = new Client([
'base_uri' => 'https://my.endpoint.com/api',
'headers' => [
'Accept' => 'application/json',
...other headers...
]
]);
$data = [...your big slab of data...];
$response = $client->post('/kitely/path', ['json' => $data]);
// a string containing the results, which will depend on the endpoint
// the Accept header says we will accept json if it is available
// then we can use json_decode on the result
$result = $response->getBody()->getContents();

I'm using Unirest to make any sort of HTTP requests. I tried using Guzzle, but was facing the same issue as you are.
So what I did was install Unirest in my project, all the process are given in details in their documentation. This works perfectly fine for me.

Related

Cannot send an empty message 50006 when using multipart Laravel Http post

I am getting this error when trying to send a message to a Discord webhook.
{"message": "Cannot send an empty message", "code": 50006}
I've read the discord documentation on sending images, and can honestly not see what I'm doing wrong.
Here's the code I'm running:
Http::withHeaders([
'Content-Type' => 'multipart/form-data; boundary=--abcdefghijklmnop'
])
->asMultipart()
->post(
$this->webhookUrl,
[
[
'name' => 'payload_json',
'contents' => '{
"content": "Hello, World!",
"embeds": [{
"title": "Hello, Embed!",
"description": "This is an embedded message.",
"thumbnail": {
"url": "attachment://image1.jpg"
},
"image": {
"url": "attachment://image2.jpg"
}
}],
"attachments": [{
"id": 0,
"description": "Image of a cute little cat",
"filename": "image1.jpg"
}, {
"id": 1,
"description": "Rickroll gif",
"filename": "image2.jpg"
}]
}',
'headers' => [
'Content-Type' => 'application/json',
]
],
[
'name' => 'image1.jpg',
'contents' => 'data:image/jpeg;base64,[[encoded image]]',
'headers' => [
'Content-Type' => 'image/jpeg',
]
],
[
'name' => 'image2.jpg',
'contents' => 'data:image/jpeg;base64,[[encoded image]]',
'headers' => [
'Content-Type' => 'image/jpeg',
]
]
];
);
As you can see, this is basically the message they use in their documentation as an example and I've just translated it to be sent with the Http facade.
What am I missing?

Tried to made an POST request using Guzzle

Im so new using API in my project, so i tried to make an POST request using Guzzle in Laravel, but i really dont know to do it, i've been seraching on the internet how to but i can't find the answer, here's what i've been tried:
$headers = [
'Content-Type' => 'application/json',
'signature' => '73ceef837b9be3cf098eca4a4697bd6a36718b64b0cf407c4324415941ff9780',
'va' => '0000002298436631',
'timestamp', '20191209155701'
];
$body = '{
"name": "Dudy",
"phone": "082298436631",
"email": "muhammadmaududy4#gmail.com",
"amount": "10000",
"notifyUrl": "https://mywebsite.com",
"expired": "24",
"expiredType": "hours",
"comments": "Catatan",
"referenceId": "1",
"paymentMethod": "qris",
"paymentChannel": "qris"
}';
$request = new Request('POST', 'https://sandbox.ipaymu.com/api/v2/payment/direct',
$headers, $body);
And i tried to do it on postman and its work perfectly, here's the setting on my postman:
You can use Laravel's Http Facade to deal with requests (easier to test later, if needed):
$headers = [];
$body = [];
$request = Http::send(
method: 'POST',
url: 'https://your.url/',
options: [
'headers' => $headers,
'form_params' => $body,
]
);
$response = Http::withHeaders([
'X-First' => 'foo',
'X-Second' => 'bar'
])->post('http://example.com/users', [
'name' => 'Taylor',
]);
I show a example code on top. I provide your code below.
$response = Http::withHeaders ([
'Content-Type' => 'application/json',
'signature' => '73ceef837b9be3cf098eca4a4697bd6a36718b64b0cf407c4324415941ff9780',
'va' => '0000002298436631',
'timestamp', '20191209155701'
])->post('https://sandbox.ipaymu.com/api/v2/payment/direct',[
"name": "Dudy",
"phone": "082298436631",
"email": "muhammadmaududy4#gmail.com",
"amount": "10000",
"notifyUrl": "https://mywebsite.com",
"expired": "24",
"expiredType": "hours",
"comments": "Catatan",
"referenceId": "1",
"paymentMethod": "qris",
"paymentChannel": "qris"
]);
Try this
$client = new \GuzzleHttp\Client();
$response = $client->post(
'https://sandbox.ipaymu.com/api/v2/payment/direct',
[
'form_params' => [
"name" => "Dudy",
"phone" => "082298436631",
"email" => "muhammadmaududy4#gmail.com",
"amount" => "10000",
"notifyUrl" => "https://mywebsite.com",
"expired" => "24",
"expiredType" => "hours",
"comments" => "Catatan",
"referenceId" => "1",
"paymentMethod" => "qris",
"paymentChannel" => "qris"
]
],
[
'headers' => [
'Content-Type' => 'application/json',
'signature' => '73ceef837b9be3cf098eca4a4697bd6a36718b64b0cf407c4324415941ff9780',
'va' => '0000002298436631',
'timestamp', '20191209155701'
]
]
);
dd($response) //response data

Laravel 8 - Get value from api json response

I am trying to get the value from 'title' in an API JSON response in Laravel 8.
{
"kind": "search#companies",
"page_number": 1,
"items_per_page": 20,
"total_results": 1,
"items": [
{
"kind": "searchresults#company",
"links": {
"self": "/company/13082103"
},
"title": "BITPIX LIMITED",
}
],
"start_index": 0
}
The call is setup and it works as expected but I am unsure how to get the variable.
The call will only ever return 1 response within items[] as the search is based on id.
Here is my method
$company = Auth::user()->companies()->first();
$apiKey = env("COMPANIES_HOUSE");
$query = $request->validate([
'query' => 'required',
]);
$response = Http::withHeaders([
'Authorization' => 'Basic ' . $apiKey,
'Connection' => 'keep-alive',
'Accept-Encoding' => 'gzip, deflate, br',
'Accept' => '*/*'
])->get('https://api.companieshouse.gov.uk/search/companies?q=' . $query['query']);
$data = json_decode($response->body());
//dd($data);
$provider = $company->providers()->create([
'name' => $data['items'][0]->title
]);
which produces this error:
Cannot use object of type stdClass as array relating to the ->create line
Many thanks for any help you can provide.
you have to decode the json you have recieved then extract the data you want:
$value = '{ "kind": "search#companies", "page_number": 1, "items_per_page": 20, "total_results": 1, "items": [{ "kind": "searchresults#company", "links": { "self": "/company/13082103" }, "title": "BITPIX LIMITED" }], "start_index": 0 }';
$decodeValue = json_decode($value);
$firstTitle = $decodeValue->items[0]->title; // first title is BITPIX LIMITED

Missing Request Body using Guzzle 6 in Laravel 5.7 working over Sage API 3.1

According to the SAGE API 3.1 manual, to create an invoice you must pass the following:
POST /sales_invoices
Content-Type: application/json
Accept: */*
{
"sales_invoice": {
"contact_id": "14d93840783b11e8990a122c8428e4b2",
"date": "2018-06-24",
"invoice_lines": [
{
"description": "A Minimal Invoice Item",
"ledger_account_id": "4195173e75db11e8990a122c8428e4b2",
"quantity": "1",
"unit_price": "0.99",
"tax_rate_id": "584793ca75db11e8990a122c8428e4b2"
}
]
}
}
Well, On my code
$client = new Client();
$endpoint = $this->endpoint.'/'.$this->action; // https://api.accounting.sage.com/v3.1/sales_invoices
$response = $client->post($endpoint, [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$this->token // My token valid
],
'form_params' => $this->params
]);
My params
"sales_invoice" => array:3 [
"contact_id" => "a39b46d1cb8a4f5a9048c32f7895147c"
"date" => "2018-03-04"
"invoice_lines" => array:1 [
0 => array:5 [
"description" => "Factura creada por error"
"ledger_account_id" => "49131457ee4f11e8ae720268dc652fba"
"quantity" => "1"
"unit_price" => "0"
"tax_rate_id" => "ES_EXEMPT"
]
]
]
]
And Guzzle extended error show problems in sales_invoice[invoice_lines] that missings values.
[{
"$severity": "error",
"$dataCode": "Validation",
"$message": "sales_invoice[invoice_lines] is invalid",
"$source": "sales_invoice[invoice_lines]"
}, {
"$severity": "error",
"$dataCode": "Validation",
"$message": "sales_invoice[invoice_lines] is invalid",
"$source": "sales_invoice[invoice_lines]"
}, {
"$severity": "error",
"$dataCode": "Validation",
"$message": "sales_invoice[invoice_lines] is invalid",
"$source": "sales_invoice[invoice_lines]"
}, {
"$severity": "error",
"$dataCode": "Validation",
"$message": "sales_invoice[invoice_lines][0][description] is missing",
"$source": "sales_invoice[invoice_lines][0][description]"
}, {
"$severity": "error",
"$dataCode": "Validation",
"$message": "sales_invoice[invoice_lines][0][ledger_account_id] is missing",
"$source": "sales_invoice[invoice_lines][0][ledger_account_id]"
}, {
"$severity": "error",
"$dataCode": "Validation",
"$message": "sales_invoice[invoice_lines][0][unit_price] is missing",
"$source": "sales_invoice[invoice_lines][0][unit_price]"
}]
What is wrong on this code?
Instead of sending it via form_params, send the payload as json:
$response = $client->post($endpoint, [
'headers' => [
'Authorization' => 'Bearer '.$this->token // My token valid
],
'json' => $this->params
]);
The content type header application/json is added automatically.

Google Analytics API - Ruby as code base

Below I have the results from google analytics API. This is the output of the query I am running from developers.google.com.
"start-date": "2015-04-01",
"end-date": "today",
"dimensions": "ga:source",
"metrics": [
"ga:users"
],
"sort": [
"-ga:users"
],
{
"name": "ga:source",
"columnType": "DIMENSION",
"dataType": "STRING"
},
{
"name": "ga:users",
"columnType": "METRIC",
"dataType": "INTEGER"
}
],
"totalsForAllResults": {
"ga:users": "2201795"
},
"rows": [
[
"(direct)",
"869648"
],
[
"sa",
"591843"
],
What I am trying to do in my code (ruby) is pull out the information from "rows". I need both the referral name "sa" and the user count "591843".
Here is how I am attempting to do this.
sa_referral = client.execute(:api_method => analytics.data.ga.get, :parameters => {
'ids' => "ga:" + saprofileID,
'dimensions' => "ga:fullreferrer",
'metrics' => "ga:users",
'sort' => "-ga:users",
'filters' => "ga:ga:source!=us-mg6.mail.yahoo.com;ga:source!=sa;ga:source!=(direct);ga:source!=mail.google.com;ga:source!=us-mg5.mail.yahoo.com;ga:source!=SA;ga:source!=m.mg.mail.yahoo.com;ga:source!=mail.aol.com;ga:source!=us-mg4.mail.yahoo.com;ga:source!=yahoo;ga:source!=bing;ga:source!=google;ga:source!=weibo;ga:fullreferrer!=eccie.net/showthread.php",
'start-date' => startDate,
'end-date' => endDate,
})
sa_referral_data = sa_referral.rows do |row|
rows.map{|r| { referrals:r[0], members:r[1] }}
end
puts sa_referral_data
The result of puts sa_referral_data is the following
scheduler caught exception:
undefined method `rows' for #<Google::APIClient::Result:0x000000044651f0>
It seems like the API is not getting the information from rows at all. Is there a way I can troubleshoot the API to see why it is losing the data for the "rows" section?
instead of sa_referral.rows, use sa_referral.each
Example code from my project..... It uses the same method to query google and return results.
result = client.execute(
:api_method => api.users.list,
:parameters => { 'domain' => domain,
'orderBy' => 'givenName',
'maxResults' => 200,
'pageToken'=> pageToken,
#'fields' => 'users(id,etag,primaryEmail,name,suspended)',
'fields' => 'nextPageToken,users(primaryEmail,suspended)',
'query' => "orgUnitPath=#{orgUnitPath}"
}
)
#pp result # There should be results here
#pp result.methods #Displays what commands you can use on the object
returnabledata = Array.new;
result.data.users.each do |user|
if user["suspended"] == false
returnabledata << user["primaryEmail"]
end
end

Resources