GitLab API `400 Bad Request` response: Bad Request - php

I am working on GitLab API to commit an mp3 file and it was working for years without having problems and the last few weeks it is throwing errors
GuzzleHttp\Exception\ClientException: Client error: `POST https://gitlab.com/api/v4/projects/.../repository/commits/` resulted in a `400 Bad Request` response in file vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on line 113
Here is the code I am using,
$client = new Client([
// Base URI is used with relative requests
'base_uri' => 'https://gitlab.com/',
// You can set any number of default request options.
'timeout' => 300,
]);
$files = [
[
'name' => 'branch',
'contents' => 'TEST'
],
[
'name' => 'commit_message',
'contents' => 'Some message'
],
[
'name' => 'actions[][action]',
'contents' => 'update'
],
[
'name' => 'actions[][file_path]',
'contents' => 'gitlab filepath/test.mp3'
],
[
'name' => 'actions[][content]',
'contents' => file_get_contents('localfilepath/test.mp3')
],
];
$response = $client->request('POST', '/api/v4/projects/.../repository/commits/', [
'headers' => [
'PRIVATE-TOKEN' => $TOKEN
],
'multipart' => $files
]);
return $response->getBody()->getContents();
```
Thanks in Advance

create-new-file-in-repository
POST /projects/:id/repository/files/:file_path
curl --request POST --header 'PRIVATE-TOKEN: <your_access_token>' \
--header "Content-Type: application/json" \
--data '{"branch": "master", "author_email": "author#example.com", "author_name": "Firstname Lastname", \
"content": "some content", "commit_message": "create a new file"}' \
"https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fproject%2Erb"
Parameters:
file_path (required) - URL encoded full path to new file. Ex. lib%2Fclass%2Erb
branch (required) - Name of the branch
start_branch (optional) - Name of the branch to start the new commit from
encoding (optional) - Change encoding to base64. Default is text.
author_email (optional) - Specify the commit author’s email address
author_name (optional) - Specify the commit author’s name
content (required) - File content
commit_message (required) - Commit message
Although the document shows that the param of "author_email" and "author_name " is optional, but without these two params will report 400 error, plus then works well

Related

Symfony 4 - URI must be a string or UriInterface - Guzzle

When I try to make a request by PHP Guzzle 7 I am getting the ([2021-10-05 15:50:44] request.CRITICAL: Uncaught PHP Exception InvalidArgumentException: "A 'contents' key is required" at /home/allen/Documents/pim/pim-community-standard/vendor/guzzlehttp/psr7/src/MultipartStream.php line 86 {"exception":"[object] (InvalidArgumentException(code: 0): A 'contents' key is required at /home/allen/Documents/pim/pim-community-standard/vendor/guzzlehttp/psr7/src/MultipartStream.php:86)"} [])
I am trying you upload a picture in Akeneo Pim 5, the endpoint documentation is:
Akeneo Pim 5 - API Documentation
Someone know what I am doing wrong?
Image 01 - Postman
Image 02 - Postman
This request on postman works fine, but I am trying to do it with a guzzle, I already have the first request getting the token.
My Request:
$client2 = new Client();
$file = '/tmp/T_square.jpg';
$url2 = "http://akeneo-pim.local/api/rest/v1/media-files";
$response2 = $client2->request('POST', $url2, [
'headers' => [
'Authorization' => 'Bearer ' . $response->access_token,
'Content-Type' => 'multipart/form-data',
'Accept' => 'application/x-www-form-urlencoded'
],
'multipart' => [
'product' => [
"identifier" => "teste_image",
"attribute" => "picture",
"locale" => null,
"scope" => null
],
'file' => fopen($file, 'r'),
]
]);

Uploaded file opened using fopen error in guzzle json_encode error: Type is not supported

I cannot attach the uploaded file. I see that fopen($image->getPathname(),'r') returns not convertible json data type making guzzle return error json_encode error: Type is not supported. What am I doing wrong here? Thank you.
stream resource #586 ▼
timed_out: false
blocked: true
eof: false
wrapper_type: "plainfile"
stream_type: "STDIO"
mode: "r"
unread_bytes: 0
seekable: true
uri: "\Temp\php2D41.tmp"
options: []
//use Illuminate\Support\Facades\Http;
//use Illuminate\Support\Facades\File;
if($request->hasFile('imgInp1'))
{
foreach(request('imgInp1') as $image)
{
$message = Http::post('https://graph.facebook.com/v9.0/me/message_attachments?access_token='.$access_token,
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
'multipart' => [
'name' => 'image',
'image_path' => $image->getPathname(),
'image_mime' => $image->getmimeType(),
'image_org' => $image->getClientOriginalName(),
'contents' => fopen($image->getPathname(), 'r'),
],
'message'=>[
'attachment' => [
'type' => 'image',
'payload' => [
"is_reusable"=> true,
],
],
],
]);
}
}
From the url you used this is the curl request provided in facebook api_guide
curl \
-F 'message={"attachment":{"type":"image", "payload":{"is_reusable":true}}}' \
-F 'filedata=#/tmp/shirt.png;type=image/png' \
"https://graph.facebook.com/v9.0/me/message_attachments?access_token=<PAGE_ACCESS_TOKEN>"
This is what -F means in curl
-F, --form <name=content>
 (HTTP SMTP IMAP) For HTTP protocol family, this lets curl emu‐
late a filled-in form in which a user has pressed the submit
button. This causes curl to POST data using the Content-Type
multipart/form-data according to RFC 2388.
(Source: man curl)
By interpreting second line of curl,
You can also tell curl what Content-Type to use by using
'type=', in a manner similar to:
curl -F "web=#index.html;type=text/html" example.com
or
curl -F "name=daniel;type=text/foo" example.com
So it tells that you need multipart/form-data.
I am using guzzle directly inplace of using HttpClient(comes by default in laravel, comfirm from composer.json). Also I suggest to use try catch block as it is not necessary that it will always be 200 response.
$message["attachment"] = [
"type" => "image",
"payload"=> ["is_reusable"=>true]
];
try{
$client = new \GuzzleHttp\Client();
if(file_exists($image)){ // or can use \Illuminate\Support\Facades\File::exists($image)
$request = $client->post( 'https://graph.facebook.com/v9.0/me/message_attachments?access_token='.$access_token, [
// 'headers' => [], //if you want to add some
'multipart' => [
[
'name' => 'message',
'contents' => json_encode($message),
],
[
'Content-type' => $image->getmimeType(),
'name' => 'filedata',
'contents' => fopen($image->getPathname(), 'r'),
]
]
]);
if ($request->getStatusCode() == 200) {
$response = json_decode($request->getBody(),true);
//perform your action with $response
}
}else{
throw new \Illuminate\Contracts\Filesystem\FileNotFoundException();
}
}catch(\GuzzleHttp\Exception\RequestException $e){
// see this answer for https://stackoverflow.com/questions/17658283/catching-exceptions-from-guzzle/64603614#64603614
// you can catch here 400 response errors and 500 response errors
// see this https://stackoverflow.com/questions/25040436/guzzle-handle-400-bad-request/25040600
}catch(Exception $e){
//catch other errors
}

Missing parameter

I'm having trouble to pass the version parameter in a POST request using GuzzleHttp.
Client error: GET https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone resulted in a 400 Bad Request response: {"code":400,"sub_code":"C00005","error":"Missing a minor version parameter in the URL. To use the latest version, add th (truncated...)
This is the latest I've tried:
$client = new \GuzzleHttp\Client([
'base_uri' => 'https://gateway.watsonplatform.net/'
]);
$toneAnalyserResponse = $client->request('POST', 'tone-analyzer/api/v3/tone', [
'auth' => ['{username}', '{password}'],
'headers' => [
'Content-Type' => 'text/plain',
],
'form_params' => [
'version' => '2017-09-21',
'tone_input' => $text,
'sentences' => true
]
]);
This was failing too:
$client = new \GuzzleHttp\Client([
'base_uri' => 'https://gateway.watsonplatform.net/'
]);
$toneAnalyserResponse = $client->request('POST', 'tone-analyzer/api/v3/tone', [
'auth' => ['{username}', '{password}'],
'headers' => [
'Content-Type' => 'text/plain',
],
'version' => '2017-09-21',
'tone_input' => $text,
'sentences' => true
]);
Failing as well if using GET instead of POST.
If I change the URI and add the version, then it works fine (well, it fails as it doesn't have the text to analyse in the request):
Change: tone-analyzer/api/v3/tone
To: tone-analyzer/api/v3/tone?version=2017-09-21
So, I guess the question is HOW DO YOU PASS URL PARAMETERS in a request using GuzzleHttp?
Note: my CURL command works fine (http 200):
curl -X POST -u "{username}":"{password}" --header 'Content-Type: text/plain' --header 'Accept: application/json' --header 'Content-Language: en' --header 'Accept-Language: en' -d 'I hate these new features On #ThisPhone after the update.\r\n \
I hate #ThisPhoneCompany products, you%27d have to torture me to get me to use #ThisPhone.\r\n \
The emojis in #ThisPhone are stupid.\r\n \
#ThisPhone is a useless, stupid waste of money.\r\n \
#ThisPhone is the worst phone I%27ve ever had - ever 😠.\r\n \
#ThisPhone another ripoff, lost all respect SHAME.\r\n \
I%27m worried my #ThisPhone is going to overheat like my brother%27s did.\r\n \
#ThisPhoneCompany really let me down... my new phone won%27t even turn on.' 'https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone?version=2017-09-21&sentences=true'
You need to send "query" parameter for querystring. Pleaes check the below codes:
$toneAnalyserResponse = $client->request('POST', 'tone-analyzer/api/v3/tone', [
'auth' => ['{username}', '{password}'],
'headers' => [
'Content-Type' => 'text/plain',
],
'query' => [
'version' => '2017-09-21'
]
]);

How to send data to CloudFlare API?

I'm trying to delete files from my CloudFlare cache using PHP. Using Guzzle I've done this:
$client = new \GuzzleHttp\Client;
$response = $client->delete('https://api.cloudflare.com/client/v4/zones/myzoneid/purge_cache', [
'query' => [
'files' => 'https://example.com/styles.css,
],
'headers' => [
'X-Auth-Email' => 'myemail',
'X-Auth-Key' => 'myapikey',
],
]);
But when I run this I get an error:
Client error: DELETE https://api.cloudflare.com/client/v4/zones/myzoneid/purge_cache?files=https%3A%2F%2Fexample.com/etc resulted in a 400 Bad Request response: {"success":false,"errors":[{"code":1012,"message":"Request must contain one of \"purge_everything\", \"files\", \"tags\" (truncated...)
I can't get it to work using Postman either. I put in the required headers and try to set a key of files or files[] with the URL but it doesn't work. I've also tried data with raw JSON as the value like {"files":["url"]} (along with a JSON content-type header) but get the same error. It thinks I'm not sending the files key.
The method for purge_cache is POST instead of DELETE (Source: https://api.cloudflare.com/#zone-purge-files-by-url).
The payload is not sent as 'query', but as 'json'.
Files should be an array, not a string.
So the correct syntax should be....
$client = new \GuzzleHttp\Client;
$response = $client->post('https://api.cloudflare.com/client/v4/zones/myzoneid/purge_cache', [
'json' => [
'files' => ['https://example.com/styles.css'],
],
'headers' => [
'X-Auth-Email' => 'myemail',
'X-Auth-Key' => 'myapikey',
],
]);

convert JSON to guzzle php librairy request

I'm trying to covert a curl to guzzle request, here is the curl request.
curl https://{subdomain}.zendesk.com/api/v2/tickets.json \
-d '{"ticket": {"subject": "My printer is on fire!", "comment": { "body": "The smoke is very colorful." }}}' \
-H "Content-Type: application/json" -v -u {email_address}:{password} -X POST
here is the JSON portion:
{
"ticket": {
"requester": {
"name": "The Customer",
"email": "thecustomer#domain.com"
},
"subject": "My printer is on fire!",
"comment": {
"body": "The smoke is very colorful."
}
}
}
Here is my broken PHP code.
$client = new GuzzleHttp\Client();
$res = $client->post('https://midnetworkshelp.zendesk.com/api/v2/tickets/tickets.json', [
'query' => [
'ticket' => ['subject' => 'My print is on Fire'], [
'comment' => [
'body' => 'The smoke is very colorful'] ], 'auth' => ['email', 'Password']]);
echo $res->getBody();
I keep getting access unauthorized for the user, however when I fire the curl command it works fine.
Any idea on what I'm possibly missing here?
Thank you
Ref:
http://curl.haxx.se/docs/manpage.html
http://guzzle.readthedocs.org/en/latest/clients.html
https://github.com/guzzle/log-subscriber
http://guzzle.readthedocs.org/en/latest/clients.html#json
Your biggest issue is that you are not converting your curl request properly.
-d = data that is being posted. In other words this is the body of your request.
-u = the username:pw that is being used to authenticate your request.
-H = extra headers that you want to use within your request.
-v = verbose output.
-X = specifies the request method.
I would recommend instanciating your client as follows:
$client = new GuzzleHttp\Client([
'base_url' => ['https://{subdomain}.zendesk.com/api/{version}/', [
'subdomain' => '<some subdomain name>',
'version' => 'v2',
],
'defaults' => [
'auth' => [ $username, $password],
'headers' => ['Content-Type' => 'application/json'], //only if all requests will be with json
],
'debug' => true, // only for debugging purposes
]);
This will:
Ensure that multiple subsequent requests made to the api will have the authentication information. Saving you from having to add it to each and every request.
Ensure that multipl subsequent (actually all) requests made with this client will contain the specified header. Saving you from having to add it to each and every request.
Provides some degree of future proofing (moving subdomain and api version into editable fields).
If you choose to log your request and response objects you can also do:
// You can use any PSR3 compliant logger in space of "null".
// Log the full request and response messages using echo() calls.
$client->getEmitter()->attach(new GuzzleHttp\Subscriber\Log\LogSubscriber(null, GuzzleHttp\Subscriber\Log\Formatter::DEBUG);
Your request will then simply become:
$json = '{"ticket": {"subject": "My printer is on fire!", "comment": { "body": "The smoke is very colorful." }}}';
$url = 'tickets/tickets.json';
$request = $client->createRequest('POST', $url, [
'body' => $json,
]);
$response = $client->send($request);
or
$json = '{"ticket": {"subject": "My printer is on fire!", "comment": { "body": "The smoke is very colorful." }}}';
$url = 'tickets/tickets.json';
$result = $client->post(, [
'body' => $json,
]);
Edit:
After futher reading Ref 4 more thouroughly it should be possible to do the following:
$url = 'tickets/tickets.json';
$client = new GuzzleHttp\Client([
'base_url' => ['https://{subdomain}.zendesk.com/api/{version}/', [
'subdomain' => '<some subdomain name>',
'version' => 'v2',
],
'defaults' => [
'auth' => [ $username, $password],
],
'debug' => true, // only for debugging purposes
]);
$result = $client->post($url, [
'json' => $json, // Any PHP type that can be operated on by PHP’s json_encode() function.
]);
You shouldn't be using the query parameter, as you need to send the raw json as the body of the request (Not in parameters like you are doing.) Check here for information on how to accomplish this. Also, be sure to try to enable debugging to figure out why a request isn't posting like you want. (You can compare both curl and guzzles debug output to verify they match).

Categories