Php, Guzzle, Schema validation failed but working in curl - php

I'm in the process of convert from cURL to Guzzle, and got most of it working.
GET requests working great etc.
My problem is the POST request, getting Schema validation errors.
It works in curl, so I'm a bit confused... well, a lot.
Client error: `POST https://restapi.e-conomic.com/customers` resulted in a `400 Bad Request` response:
{"message":"Schema validation failed.","errorCode":"E00500"
I hope one of you can tell me, if I did something wrong in the convert? Maybe my arrays needs to be formatted in another way.
This is my old working "cURL code":
$data = array(
'name' => 'Test User',
'address' => 'Road 123',
'email' => 'morten#domain.com',
'zip' => '9000',
'city' => 'City',
'country' => 'Danmark',
'corporateIdentificationNumber' => '12345678',
'customerGroup' => array(
'customerGroupNumber' => 1
),
'currency' => 'DKK',
'paymentTerms' => array(
'paymentTermsNumber' => 1
),
'vatZone' => array(
'vatZoneNumber' => 1
)
);
$options = array(
CURLOPT_URL => 'https://restapi.e-conomic.com/customers',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => array(
'X-AppSecretToken:[removed]',
'X-AgreementGrantToken:[removed]',
'Content-Type:application/json; charset=utf-8'
),
CURLOPT_POSTFIELDS => json_encode($data)
);
curl_setopt_array($ch, $options);
This is my new "guzzle code", that is causing me problems:
$client = new GuzzleHttp\Client();
$headers = [
'X-AppSecretToken' => '[removed]',
'X-AgreementGrantToken' => '[removed]',
'Content-Type' => 'application/json;charset=utf-8',
'debug' => false
];
$form_params = [
'name' => 'Test User',
'address' => 'Road 123',
'email' => 'test#email.dk',
'zip' => '9000',
'city' => 'City',
'country' => 'Danmark',
'corporateIdentificationNumber' => '12345678',
'customerGroup' => [
'customerGroupNumber' => 1
],
'currency' => 'DKK',
'paymentTerms' => [
'paymentTermsNumber' => 1
],
'vatZone' => [
'vatZoneNumber' => 1
]
];
$response = $client->post('https://restapi.e-conomic.com/customers', [
'headers' => $headers,
'form_params' => $form_params
]);
I tried to use the "body" parameter, as stated in the Guzzle documentation, but received this error:
Passing in the "body" request option as an array to send a POST request has been deprecated. Please use the "form_params" request option to send a application/x-www-form-urlencoded request, or the "multipart" request option to send a multipart/form-data request.
I'm not sure what to do and really hope, that one of you guys will tell me what i'm doing wrong.
https://restapi.e-conomic.com/schema/customers.post.schema.json#_ga=2.167601086.1488491524.1500877149-796726383.1499933074
https://restdocs.e-conomic.com/#post-customers

I had to post the quest as json:
$response = $client->post('https://restapi.e-conomic.com/customers', [
'headers' => $headers,
'json' => $form_params
]);

Related

Odd problem with PHP Curl and guzzle in Laravel

I'm trying to interact with a WS. This WS accept post requests in multipart and also in x-www-urlencoded. The WS is an OCR service, you send a passport picture and the WS returns a json with the MRZ data.
When I try the WS with postman always works, I send any photo of any size (I tested with 5Mb photo) and always works. When I send the exactly the same data using Curl or Guzzle, if the photo is about 30-50Kb the WS works as expected, but when I send a larger image, for example 500Kb, then the WS doesn't work.
I can access to the Ws code because it's propietary. I just trying to understand why is this happen. This is the multipart function
$url='http://10.0.20.113:8080/';
$req = new Client(['verify' => 0]);
$response = $req->post(
$url, [
'headers' => [
'accept-encoding' => 'gzip, deflate, br',
'accept' => '*/*'
],
'multipart' => [
[
'name' => 'user',
'contents' => 'admin'
],
[
'name' => 'pwd',
'contents' => 'admin'
],
[
'name' => 'doctype',
'contents' => '0'
],
[
'name' => 'new',
'contents' => '1'
],
[
'name' => 'pressmode',
'contents' => '2'
],
[
'name' => 'image1',
'contents' => $img1
],
[
'name' => 'image2',
'contents' => $img2,
]
],
]
);
Log::info('Response received');
return $response->getBody()->getContents();
this is another try with curl
$ch = curl_init();
$headers = array();
$post = array('user' => 'admin', 'pwd' => 'admin', 'doctype' => 0, 'new' => 1, 'pressmode' => 2, 'image1' => $img1, 'image2' => $img2); // e.g. $fieldName = 'image'
curl_setopt_array(
$ch,
[
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_URL => $url,
CURLOPT_POSTFIELDS => $post,
CURLOPT_SSL_VERIFYPEER => 0
]
);
$result = curl_exec($ch);
$response = curl_getinfo($ch);
Finally it was a apache issue in the WS side. Using curl, when the request size is more than 1024 bytes, then curl send a expect:100-continue header.
When the server receives this header, it should respond with an http 100 code, indicating to the client that it can continue transmission.
Postman doesn't use this header even with large requests.
The WS use a embedded apache to serve the requests, which I presume that has a bug (there is at least to bugs related to that) that makes apache doesn't return the http 100 code. Therefore curl aborts the request.

How do i send a PUT request in Laravel

I am trying to update data through sending an http put request to ServiceDesk plus api. When using the console that comes with the system, it works well but when I try to send a request to the same api from Laravel it does not work.
request from the console below
I am trying to send a request to the same url using the code below.
private function openTicket($notification)
{
$data = json_encode(['input_data' => ['request' => ['subject' => $notification->subject,
'description' => $notification->description,
'status' => ['name' => 'Open']]]]);
$request_id = $notification->request_id;
$response = Http::withHeaders([
'technician_key' => 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX',
'Accept' => 'application/json'
])->put('http://localhost:8082/api/v3/requests/' . $request_id, $data);
dd($response);
}
and im getting an error 400 bad request.
You should not do json_encode, laravel Http module will automatically do it for you. I think your data is json_encoded twice right now.
$data = [
'input_data' => [
'request' => [
'subject' => $notification->subject,
'description' => $notification->description,
'status' => ['name' => 'Open']
]
]
]);
$request_id = $notification->request_id;
$response = Http::withHeaders([
'technician_key' => 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX',
'Accept' => 'application/json'
])->put('http://localhost:8082/api/v3/requests/' . $request_id, $data);
dd($response);
I just noticed. From the documentation you provided in the screenshot, the input_data nesting level in the array should not exist
$data = [
'request' => [
'subject' => $notification->subject,
'description' => $notification->description,
'status' => ['name' => 'Open']
]
]);
I managed to find a solution and it is as follows,
private function openTicket($notification): bool
{
$data = json_encode(['request' => ['subject' => $notification->subject,
'description' => $notification->description,
'status' => ['name' => 'Open']]]);
$request_id = $notification->request_id;
$response = Http::withHeaders([
'technician_key' => 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
'Content-Type' => 'application/x-www-form-urlencoded'
//added asForm() before put
])->asForm()->put('http://localhost:8082/api/v3/requests/' . $request_id, [
'input_data' => $data
]);
if ($response->status() == 200) {
return true;
}
return false;
}
I added asForm() before the put function. This is because asForm() indicates that the request contains form parameters. I also modified the $data object from
$data = json_encode(['input_data' => ['request' => ['subject' => $notification->subject,
'description' => $notification->description,
'status' => ['name' => 'Open']]]]);
to
$data = json_encode(['request' => ['subject' => $notification->subject,
'description' => $notification->description,
'status' => ['name' => 'Open']]]);
Then it worked as i had expected.

Why is Guzzle POST showing this foreach error?

I am using
"guzzlehttp/guzzle": "^6.3"
and I am running
$client = new \GuzzleHttp\Client([
'base_uri' => 'http://myapp.loc',
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
]
]);
Then
$response = $client->post('/api/books', [
'json' => [
'bookId' => '123',
'title' => 'My Random Test Book',
'author' => 'Test Author'
]
]);
But I get
GuzzleHttp\Exception\ClientException : Client error: POST http://myapp.loc/api/books resulted in a 404 Not Found response:
Invalid argument supplied for foreach()
If I use the same route and data in Postman everything works, so the route and method is ok.
I have tried also
$response = $client->post('/api/books', [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'body' => json_encode([
'bookId' => '123',
'title' => 'My Random Test Book',
'author' => 'Test Author'
])
]);
but it returns the same foreach error.
Any ideas on why Guzzle is showing this foreach error?
Digging a bit into this with Xdebug, the error arises from \GuzzleHttp\Psr7\Stream at the fread point
public function read($length)
{
...
$string = fread($this->stream, $length);
So the solution was to form the request like:
$response = $client->request('POST', 'http://myapp.loc/api/books', [
'form_params' => [
'parameters' => json_encode([[
'bookId' => '123',
'title' => 'My Random Test Book',
'author' => 'Test Author'
]])
]
]);

Struggling with s3 multipart upload guzzle for Eventbrite

I'm trying to upload to s3 based on the documentation in Eventbrite but I'm getting nowhere. I think it's down to the structure of my request but I've tried multiple different things and nothing is really working and I get a 'Bucket POST must contain a field named 'key' error.
The instructions are here, so it provides you with a presigned POST object, but I can't figure out how to then provide those details in Guzzle
https://www.eventbrite.com/developer/v3/resources/uploads/
I would use the s3client but I don't think it's suitable, as I do not have the region name.
So this is the array back from EB, as given in the documentation
$postFields = [
'key' => $post_args['key'],
'AWSAccessKeyId' => $post_args['AWSAccessKeyId'],
'bucket' => $post_args['bucket'],
'acl' => $post_args['acl'],
'signature' => $post_args['signature'],
'policy' => $post_args['policy'],
];
and I've tried various structures:
$args = [
'query' => $postFields,
'multipart' => [
[
'name' => $instructions_response['body']['file_parameter_name'],
'Content-type' => 'multipart/form-data',
'contents' => $image,
]
],
]
Or
$args = [
'multipart' => [
[
'key' => $post_args['key'],
'AWSAccessKeyId' => $post_args['AWSAccessKeyId'],
'bucket' => $post_args['bucket'],
'acl' => $post_args['acl'],
'signature' => $post_args['signature'],
'policy' => $post_args['policy'],
'name' => $instructions_response['body']['file_parameter_name'],
'Content-type' => 'multipart/form-data',
'contents' => $image,
]
],
];
Or
$args = [
'key' => $post_args['key'],
'AWSAccessKeyId' => $post_args['AWSAccessKeyId'],
'bucket' => $post_args['bucket'],
'acl' => $post_args['acl'],
'signature' => $post_args['signature'],
'policy' => $post_args['policy'],
'multipart' => [
[
'name' => $instructions_response['body']['file_parameter_name'],
'Content-type' => 'multipart/form-data',
'contents' => $image,
]
],
];
(Plus a bunch of more spurious ones that I can't remember anymore)
Anyway, I'm stuck. I just can't think how this POST data is meant to be structured for it to post to S3. I've gone down the rabbit hole with Xdebug and it's still not clear what is even going on when it makes the request tbh
Request called like so
$upload_response = $this->client->request('POST', $upload_url, $args);
UPDATE: It was pointed out to me that whilst 'key' is lowercase in the error message and what comes back from aws, it's capitalised in the documentation. I changed it to 'Key' and now I get 'Conflicting query string parameters: acl, policy'

convert curl to guzzle

i have this perfectly working curl command:
curl -i --data "site=walletgroove.com&placement=above&device=desktop&source=*&campaign=*&url=*&country=*&active=1" http://10.0.0.38/adserver/src/public/api/rule
which i tried to execute with guzzle but for some reason i keep getting error from my code, an exception to be more accurate. this exception is thrown when params are not passed properly.
this is one of few tries i had:
public function testApi_postRule()
{
$client = new Client();
$client->post('http://10.0.0.38/adserver/src/public/api/rule',[ 'query' => [
'site' => 'walletgroove.com',
'placement' => 'guzzle_unique_placement',
'device' => 'desktop',
'source' => 'guzzource',
'campaign' => '*',
'country' => '*',
'url' => '*',
'active' => '1'
]]);
}
any idea what am i doing wrong here??
You are passing the query parameter, which appends a query string instead of sending in the request body. For a POST request, you probably want to use form_params as shown in the documentation.
$client->post('http://10.0.0.38/adserver/src/public/api/rule', [
'form_params' => [
'site' => 'walletgroove.com',
'placement' => 'guzzle_unique_placement',
'device' => 'desktop',
'source' => 'guzzource',
'campaign' => '*',
'country' => '*',
'url' => '*',
'active' => '1'
]
]);

Categories