I'm implementing third party API in Laravel where I have to send some data along with fileData with base64.
Like this:
To post the data I'm sending like this:
$requestUrl = $this->baseUrl . $endpoint;
$content = [
'associatedType' => 'property',
'associatedId' => 'XXXXXXX81',
'typeId' => 'DET',
'name' => '304-Smithson-Road-Details.pdf',
"isPrivate" => false,
'fileData' => 'data:application/pdf;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=='
];
$response = Http::withHeaders([
"api-version" => config("apiVersion"),
"customer" => config("customer"),
"Accept" => "application/json-patch+json",
"Authorization" => "Bearer {$this->token}"
])->send($method, $requestUrl, [
"body" => json_encode($content)
])->collect()->toArray();
return $response;
After executing the above code I'm getting null response and file is not uploaded.
Is there any mistake in HTTP request code?
Related
I have the following Postman request for testing a third party API;
What I am trying to do is convert this into code using Laravel's HTTP class, the code i currently have is;
public function uploadToThridParty()
{
$uploadContents = [
'id' => 'this-is-my-id',
'fileUpload' => true,
'frontfile' => Storage::get('somefrontfile.jpg'),
'sideview' => Storage::get('itsasideview.png'),
];
$request = Http::withHeaders(
[
'Accept' => 'application/json',
]
);
$response = $request
->asForm()
->post(
'https://urltoupload.com/upload', $uploadContents
)
}
But every time I run this, the 3rd party API comes back with Invalid ID, even though if i use Postman with the same ID it works fine.
I cant seem to figure out where i am going wrong with my code;
As #Cbroe mention about attach file before sending post request you can make this like this example:
public function uploadToThridParty()
{
$uploadContents = [
'id' => 'this-is-my-id',
'fileUpload' => true
];
$request = Http::withHeaders(
[
'Accept' => 'application/json',
]
);
$response = $request
->attach(
'frontfile', file_get_contents(storage_path('somefrontfile.jpg')), 'somefrontfile.jpg'
)
->attach(
'sideview', file_get_contents(storage_path('itsasideview.png')), 'itsasideview.jpg'
)
->post(
'https://urltoupload.com/upload', $uploadContents
)
}
Also i think you need remove asForm method because it's override your header accept type to application/x-www-form-urlencoded that is way your exception is Invalid ID
Some third party API would require you to have the request with content type as multipart/form data
you can double check all the headers being pass on your postman request HEADERS tab and view on Hidden headers.
If you indeed need your request to be in multipart/form-data, You can use the multipart options of guzzle.
Although this doesnt seem to be on Laravel HTTP-Client docs, you can simply pass a asMultipart() method in your HTTP request
just check the /vendor/laravel/framework/src/Illuminate/Support/Facades/Http.php for full reference of HTTP client.
You can have your request like this.
public function uploadToThridParty() {
$uploadContents = [
[
'name' => 'id',
'contents' => 'this-is-my-id'
],
[
'name' => 'fileUpload',
'contents' => true
],
[
'name' => 'frontfile',
'contents' => fopen( Storage::path( 'somefrontfile.jpg' ), 'r')
],
[
'name' => 'sideview',
'contents' => fopen( Storage::path( 'itsasideview.jpg' ), 'r')
],
];
$request = Http::withHeaders(['Accept' => 'application/json']);
$response = $request->asMultipart()->post('https://urltoupload.com/upload', $uploadContents );
}
I have two app in Laravel. One is simple api with one controller if i send params using online tool or postman app everything is ok. i need check in headers to send 'Host' without this header i got error 400 Bad Request. But if i try send the same from my second laravel app i've got empty params request
$response = Http::asForm()->withHeaders([
'Host' => 'example.com:8091',
])->post('http://example.com:8091/abc/test/', [
'param_1' => 'abcdefgh123',
'param2' => 'blablabla',
]);
$body = $response->getBody()->getContents();
I tried asForm() and nothing. What should be in Host header ?
Try this option
$json_data = json_encode(['param_1' => 'test 1', 'param_2' => 'test 2']);
$response = Http::asForm()->post('http://example.com:8091/abc/test/', [
'body' => $json_data,
'headers' => [
'Content-Type' => 'application/json',
'Content-Length' => strlen($json_data),
]
]);
I am able to upload a file to an API endpoint using Postman.
I am trying to translate that into uploading a file from a form, uploading it using Laravel and posting to the endpoint using Guzzle 6.
Screenshot of how it looks in Postman (I purposely left out the POST URL)
Below is the text it generates when you click the "Generate Code" link in POSTMAN:
POST /api/file-submissions HTTP/1.1
Host: strippedhostname.com
Authorization: Basic 340r9iu34ontoeioir
Cache-Control: no-cache
Postman-Token: 6e0c3123-c07c-ce54-8ba1-0a1a402b53f1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="FileContents"; filename=""
Content-Type:
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="FileInfo"
{ "name": "_aaaa.txt", "clientNumber": "102425", "type": "Writeoff" }
----WebKitFormBoundary7MA4YWxkTrZu0gW
Below is controller function for saving the file and other info. The file uploads correctly, I am able to get the file info.
I think the problem I am having is setting the multipart and headers array with the correct data.
public function fileUploadPost(Request $request)
{
$data_posted = $request->input();
$endpoint = "/file-submissions";
$response = array();
$file = $request->file('filename');
$name = time() . '_' . $file->getClientOriginalName();
$path = base_path() .'/public_html/documents/';
$resource = fopen($file,"r") or die("File upload Problems");
$file->move($path, $name);
// { "name": "test_upload.txt", "clientNumber": "102425", "type": "Writeoff" }
$fileinfo = array(
'name' => $name,
'clientNumber' => "102425",
'type' => 'Writeoff',
);
$client = new \GuzzleHttp\Client();
$res = $client->request('POST', $this->base_api . $endpoint, [
'auth' => [env('API_USERNAME'), env('API_PASSWORD')],
'multipart' => [
[
'name' => $name,
'FileContents' => fopen($path . $name, 'r'),
'contents' => fopen($path . $name, 'r'),
'FileInfo' => json_encode($fileinfo),
'headers' => [
'Content-Type' => 'text/plain',
'Content-Disposition' => 'form-data; name="FileContents"; filename="'. $name .'"',
],
// 'contents' => $resource,
]
],
]);
if($res->getStatusCode() != 200) exit("Something happened, could not retrieve data");
$response = json_decode($res->getBody());
var_dump($response);
exit();
}
The error I am receiving, screenshot of how it displays using Laravel's debugging view:
The way you are POSTing data is wrong, hence received data is malformed.
Guzzle docs:
The value of multipart is an array of associative arrays, each
containing the following key value pairs:
name: (string, required) the form field name
contents:(StreamInterface/resource/string, required) The data to use in the
form element.
headers: (array) Optional associative array of custom headers to use with the form element.
filename: (string) Optional
string to send as the filename in the part.
Using keys out of above list and setting unnecessary headers without separating each field into one array will result in making a bad request.
$res = $client->request('POST', $this->base_api . $endpoint, [
'auth' => [ env('API_USERNAME'), env('API_PASSWORD') ],
'multipart' => [
[
'name' => 'FileContents',
'contents' => file_get_contents($path . $name),
'filename' => $name
],
[
'name' => 'FileInfo',
'contents' => json_encode($fileinfo)
]
],
]);
$body = fopen('/path/to/file', 'r');
$r = $client->request('POST', 'http://httpbin.org/post', ['body' => $body]);
http://docs.guzzlephp.org/en/latest/quickstart.html?highlight=file
In Laravel 8 with guzzle I am using this:
The idea is that you are reading the file with fread or file_get_content, then you can use the Laravel getPathname() which points to the file in /tmp
$response = $this
->apiClient
->setUserKey($userToken)
->post(
'/some/url/to/api',
[
'multipart' => [
'name' => 'avatar',
'contents' => file_get_contents($request->file('avatar')->getPathname()),
'filename' => 'avata.' . $request->file('avatar')->getClientOriginalExtension()
]
]
);
I'm trying to create a wrapper for a payment gateway api. I've chosen to use GuzzleHttp. Here is the basic code that I currently have. As the gateway expects input to be JSON formatted sent via HTTP POST, I tried two possible ways:
Using the json option and assigning a key-based array to it.
Explicitly setting content-type to application/json and sending a json formatted string via body.
Code:
$client = new Client([
'base_uri' => 'https://sandbox.gateway.com',
]);
$input = [
'merchant_id' => '12345-33445',
'security_key' => '**********',
'operation' => 'ping',
];
$clientHandler = $client->getConfig('handler');
$tapMiddleware = Middleware::tap(function ($request) {
foreach($request->getHeaders() as $h=>$v){
echo $h . ': ' . print_r($v) . PHP_EOL;
}
});
try {
$response = $client->post(
'/pg/auth',
[
'timeout' => 30,
'headers' => [
'Content-Type' => 'application/json',
'Cache-Control' => 'no-cache',
],
'body' => json_encode($input),
'debug' => true,
'handler' => $tapMiddleware($clientHandler)
]
);
print_r($response);
} catch(Exeption $e){
print_r($e);
}
Unfortunately, gateway got back with a 401 error although the credentials are correct. I suspect the way request is sent has an issue. I came to this conclusion as the headers printed from within the tap function are all arrays (especially content-type) instead of strings. Unlike what is described here http://guzzle.readthedocs.org/en/latest/request-options.html?highlight=request#json.
Array
(
[0] => GuzzleHttp/6.1.1 curl/7.43.0 PHP/5.5.29
)
User-Agent: 1
Array
(
[0] => sandbox.gateway.com
)
Host: 1
Array
(
[0] => application/json
)
Content-Type: 1
How about sending the request as suggested?
$client = new Client([
'base_uri' => 'https://sandbox.gateway.com',
]);
$client->request('POST', '/pg/auth', [
'timeout' => 30,
'debug' => true,
'json' => [
'merchant_id' => '12345-33445',
'security_key' => '**********',
'operation' => 'ping',
],
]);
For reference, see http://docs.guzzlephp.org/en/latest/request-options.html#json.
This should be soo simple but I have spent hours searching for the answer and am truly stuck. I am building a basic Laravel application and am using Guzzle to replace the CURL request I am making at the moment. All the CURL functions utilise raw JSON variables in the body.
I am trying to create a working Guzzle client but the server is respsonding with 'invalid request' and I am just wondering if something fishy is going on with the JSON I am posting. I am starting to wonder if you can not use raw JSON in the Guzzle POST request body? I know the headers are working as I am receiving a valid response from the server and I know the JSON is valid as it is currently working in a CURL request. So I am stuck :-(
Any help would be sooo greatly appreciated.
$headers = array(
'NETOAPI_KEY' => env('NETO_API_KEY'),
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'NETOAPI_ACTION' => 'GetOrder'
);
// JSON Data for API post
$GetOrder = '{
"Filter": {
"OrderID": "N10139",
"OutputSelector": [
"OrderStatus"
]
}
}';
$client = new client();
$res = $client->post(env('NETO_API_URL'), [ 'headers' => $headers ], [ 'body' => $GetOrder ]);
return $res->getBody();
You can send a regular array as JSON via the 'json' request option; this will also automatically set the right headers:
$headers = [
'NETOAPI_KEY' => env('NETO_API_KEY'),
'Accept' => 'application/json',
'NETOAPI_ACTION' => 'GetOrder'
];
$GetOrder = [
'Filter' => [
'OrderID' => 'N10139',
'OutputSelector' => ['OrderStatus'],
],
];
$client = new client();
$res = $client->post(env('NETO_API_URL'), [
'headers' => $headers,
'json' => $GetOrder,
]);
Note that Guzzle applies json_encode() without any options behind the scenes; if you need any customisation, you're advised to do some of the work yourself
$res = $client->post(env('NETO_API_URL'), [
'headers' => $headers + ['Content-Type' => 'application/json'],
'body' => json_encode($getOrders, ...),
]);
Guzzle 7 Here
The below worked for me with raw json input
$data = array(
'customer' => '89090',
'username' => 'app',
'password' => 'pwd'
);
$url = "http://someendpoint/API/Login";
$client = new \GuzzleHttp\Client();
$response = $client->post($url, [
'headers' => ['Content-Type' => 'application/json', 'Accept' => 'application/json'],
'body' => json_encode($data)
]);
print_r(json_decode($response->getBody(), true));
For some reasons until I used the json_decode on the response, the output wasn't formatted.
You probably need to set the body mime type. This can be done easily using the setBody() method.
$request = $client->post(env('NETO_API_URL'), ['headers' => $headers]);
$request->setBody($GetOrder, 'application/json');