I need to integrate an API into my app.
The docs say:
HTTP POST
The following is a sample HTTP POST request and response. The placeholders shown need to be replaced with actual values.
POST /partnerhubwebservice.asmx/Authorise HTTP/1.1
Host: stage.example.co.uk
Content-Type: application/x-www-form-urlencoded
Content-Length: length
username=string&password=string
and response is:
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<AuthorisationResult xmlns="http://webservice.example.co.uk/">
<Token>string</Token>
</AuthorisationResult>
Reading the docs I create this function in Laravel Controller:
public function testRld() {
$client = new GuzzleHttp\Client();
try {
$res = $client->post('http://stage.example.co.uk/partnerhubwebservice.asmx/Authorise', [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
'x-www-form-urlencoded' => [
'Username' => 'MMM_bookings',
'Password' => 'passwordaaaa',
]
]);
return $res;
}
catch (GuzzleHttp\Exception\ClientException $e) {
$response = $e->getResponse();
$result = json_decode($response->getBody()->getContents());
return response()->json(['data' => $result]);
}
}
but I got a message:
ServerException in RequestException.php line 111: Server error: POST
http://stage.example.co.uk/partnerhubwebservice.asmx/Authorise
resulted in a 500 Internal Server Error response: Missing parameter:
username.
When I try this at POSTMAN app everything is fine and there I get response ike:
<?xml version="1.0" encoding="utf-8"?>
<AuthorisationResult xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://webservice.example.co.uk/">
<RequestSuccessful>true</RequestSuccessful>
<ErrorMessage />
<Token>27d67d31-999-44e0-9851-d6f427fd2181</Token>
</AuthorisationResult>
Please help me to solve this problem? What is wrong with my code? WHy I got the error , and POSTMAN request works fine ...
Try sending username and password inside of a body as body or json, instead of as application/x-www-form-urlencoded, like so:
$res = $client->post('http://stage.example.co.uk/partnerhubwebservice.asmx/Authorise', [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
'json' => [
'username' => 'MMM_bookings',
'password' => 'passwordaaaa',
]
]);
or
$res = $client->post('http://stage.example.co.uk/partnerhubwebservice.asmx/Authorise', [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
'body' => [
'username' => 'MMM_bookings',
'password' => 'passwordaaaa',
]
]);
Use form_params:
$client->request('POST', 'http://stage.example.co.uk/partnerhubwebservice.asmx/Authorise', [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
'form_params' => [
'username' => 'MMM_bookings',
'password' => 'password'
]
]);
The PSR-7 standard specifies interfaces for HTTP messages, including requests and responses. If you would like to obtain an instance of a PSR-7 request instead of a Laravel request, you will first need to install a few libraries. Laravel uses the Symfony HTTP Message Bridge component to convert typical Laravel requests and responses into PSR-7 compatible implementations:
Install the necessary dependencies as well:
composer require symfony/psr-http-message-bridge
composer require zendframework/zend-diactoros
Related
I am creating a user with the api provided. I am using Laravel and trying to store data to smartrmail and docs to create new subscriber is here https://docs.smartrmail.com/en/articles/636615-list-subscribers
Each time i send request i get following error:
Server error: `POST https://go.smartrmail.com/api/v1/lists/1sptso/list_subscribers` resulted in a `500 Internal Server Error` response: {"error":"param is missing or the value is empty: subscribers"}
{"error":"param is missing or the value is empty: subscribers"}
I am using Laravel and my code is here
Route::get('smartrmail',function(){
$headers = [
'Accept' => 'application/json',
'Authorization' => 'token f91715d5-3aac-4db3-a133-4b3a9493a9a4',
'Content-Type' => 'application/json',
];
$client = new GuzzleHttp\Client([
'headers' => $headers
]);
$data = [
"subscribers"=>[
[
"email"=> "vanhalen#example.com",
"first_name"=> "van",
"last_name"=> "halen",
"subscribed"=> true,
]
]
];
$res = $client->request('POST', 'https://go.smartrmail.com/api/v1/lists/1sptso/list_subscribers', [
'form_params' => [
$data
]
]);
return($res);
// echo $res->getStatusCode();
});
Anybody help me to figure out what is wrong here. I am following this docs
https://docs.smartrmail.com/en/articles/636615-list-subscribers
to create a new subscriber
Instead of
'form_params' => [
$data
]
use
'json' => $data
Explanation
You want to send json data (I assume that because you set header 'Content-Type' => 'application/json', which means that you are sending json), but form_params is used for application/x-www-form-urlencoded.
json sets header to application/json and sends data as json.
As you set proper header, this should work too:
'body' => $data
Proper name of param you can find in Guzzle docs, I used uploading data part.
I have been using Guzzle for a while within my Laravel 5.8 project. It has been working with Restful API that supports JSON format.
Now that there is a new Restful API that supports only XML format. I don't know how to do that using Guzzle. Below is an example of what the HTTP request might look like.
POST: http://api.url_endpoint.com/my_api.ashx HTTP/1.1
Content-Type: application/x-www-form-url encoded
Host: http://api.url_endpoint.com
Content-Length: 467
Expect: 100-continue
Connection: Close
<Section>
<LoginDetails>
<Login>ABC</Login>
<Password>ABCDE</Password>
</LoginDetails>
</Section>
In the documentation, it says: The XML should be in the body of the request.
Question 1. How do I put XML in the body of the request?
Question 2. Note the HTTP/1.1, should it be concatenated as suffix of the API URL endpoint?
This is how I have tried.
$header_options = [
'headers' => [
'Accept' => 'application/xml',
'Content-Type' => 'application/x-www-form-url encoded',
'Host' => 'http://api.url_endpoint.com',
'Content-Length' => 467,
'Expect' => '100-continue',
'Connection' => 'Close',
],
'body' => '<Section><LoginDetails><Login>ABC</Login><Password>ABCDE</Password></LoginDetails></Section>',
];
$response = $client->request('POST', 'http://api.url_endpoint.com/my_api.ashx', $header_options);
dump($response->xml());
But I still get 400 Bad Request as response back.
First of all, try with just the fix of the Content-Type header value : application/x-www-form-urlencoded (not application/x-www-form urlencoded).
If this does not work, also try to parse the body like that :
$header_options = [
'headers' => [
...
'Content-Type' => 'application/x-www-form-urlencoded'
...
],
...
'body' => urlencode('<Section><LoginDetails><Login>ABC</Login><Password>ABCDE</Password></LoginDetails></Section>'),
];
If this does not work, could you try to change the header set that way :
$header_options = [
'headers' => [
...
'Content-Type' => 'text/xml', // also try 'application/xml'
...
],
...
];
Let me know if one of these ideas helped you :)
My Guzzle POST request to https://api.scarif.dev/auth gives back a 404, while the page exists through Postman, or browser, or javascript. It should return a 200 with a 401 message, but Guzzle gives back a 404. In both POST and GET mode that is.
I've tried multiple Client setups, including different headers and disabling SSL verification, but without any success. Now I've copied the exact same headers that made it work in postman, but still no success.
I've been searching through google and stackoverflow, but couldn't find an answer that fixed my problem.
Request in PHP:
<?php
$client = new Client([
'header' => [
'Accept' => 'application/json',
'Content-Type' => 'application/x-www-form-urlencoded'
],
'verify' => false
]);
$response = $client->request('POST', 'https://api.scarif.dev/auth', [
'form_params' => []
]);
echo $response->getBody()->getContents();
?>
Expected result:
{
"detail": "https://login.scarif.dev",
"status": 401,
"title": "Unauthorized",
"type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"
}
Actual result:
Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client
error: POST https://api.scarif.dev/auth resulted in a 404 Not
Found response:
404 Not Found Not Found
(truncated...) in
/home/admin/domains/login.scarif.dev/framework/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113
Stack trace: #0
/home/admin/domains/login.scarif.dev/framework/vendor/guzzlehttp/guzzle/src/Middleware.php(66):
GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request),
Object(GuzzleHttp\Psr7\Response)) #1
/home/admin/domains/login.scarif.dev/framework/vendor/guzzlehttp/promises/src/Promise.php(203):
GuzzleHttp\Middleware::GuzzleHttp{closure}(Object(GuzzleHttp\Psr7\Response))
2 /home/admin/domains/login.scarif.dev/framework/vendor/guzzlehttp/promises/src/Promise.php(156):
GuzzleHttp\Promise\Promise::callHandler(1,
Object(GuzzleHttp\Psr7\Response), Array) #3
/home/admin/domains/login.scarif.dev/framework/ven in
/home/admin/domains/login.scarif.dev/framework/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
on line 113
API endpoint controller:
<?php
namespace Controller;
use Core\Config;
use Core\Request;
use Core\Response;
use Model\Token;
use Model\User;
use MongoDB\BSON\UTCDateTime;
class AuthController extends Controller
{
public function view(User $user, Token $token)
{
extract(Request::getPostData());
if (isset($access_token) && !empty($access_token)) {
$_token = $token->getTokenByToken($access_token);
if (
$_token['type'] !== Token::TYPE_ACCESS_TOKEN ||
$_token['expires_on'] <= new UTCDateTime()
) {
return $this->view->display('json', [
'payload' => Response::apiResponse(
$this->config->get('url.login'), 401
)
]);
}
$token->delete($_token['_id']);
$newToken = $token->create(Token::TYPE_ACCESS_TOKEN, $_token['user_id']);
return $this->view->display('json', [
'payload' => Response::apiResponse($newToken['token'])
]);
}
if (!isset($email) || !isset($password) || empty($email) || empty($password)) {
return $this->view->display('json', [
'payload' => Response::apiResponse(
$this->config->get('url.login'), 401
)
]);
}
if (!$user->checkCredentials($email, $password)) {
return $this->view->display('json', [
'payload' => Response::apiResponse(
"The email address or password you've entered is invalid. Please check your entry and try again.",
422
)
]);
}
$user = $user->getUserByEmail($email);
$token = $token->create(Token::TYPE_ACCESS_TOKEN, $user['_id']);
return $this->view->display('json', [
'payload' => Response::apiResponse($token['token'])
]);
}
}
It seems like the issue is coming from the API you are consuming. When using your code with a different url it works just fine:
$client = new Client([
'header' => [
'Accept' => 'application/json',
'Content-Type' => 'application/x-www-form-urlencoded'
],
'verify' => false
]);
$response = $client->request('POST', 'https://jsonplaceholder.typicode.com/posts', [
'form_params' => []
]);
echo $response->getBody()->getContents();
Could you show the code for the API endpoints?
I had the same issue and was looking for solutions until I landed here. Didn't get any help online though and solutions of other people didn't work for me but later I solved myself through extensive debugging and I am sharing the solution in a hope it might help someone else in the future.
Scenario: In my case I had an API gateway and client (Postman in my case) was making request to the API gateway and gateway in turn was making request to a microservice using Guzzle 7 in Laravel 8. I used to pass all headers I received from the client to microservice as is and that was causing 404 error. When I changed that and passed only my own headers in the request to the microservice, there was light and 404 was gone.
These were default headers of Postman and I was passing in the request as is:
{
"authorization": [
"Bearer eyJ0eXAiOiJKV1 .."
],
"user-agent": [
"PostmanRuntime/7.29.0"
],
"accept": [
"*/*"
],
"postman-token": [
"ca180f3a-ec65-4212-bd9f-dc294846dc65"
],
"host": [
"sagateway.com"
],
"accept-encoding": [
"gzip, deflate, br"
],
"connection": [
"keep-alive"
]
}
I removed all of it and only passed one thing in the header:
['Authorization' => "<Key Here>"]
It then worked fine and I took a breath of relief after a few days of continuous googling.
In my Laravel application, I periodically need to POST data to an API using Guzzle.
The API users a bearer token to authenticate, and requests and accepts raw json. To test, I accessed the API using Postman, and everything worked wonderfully.
Postman Headers:
Accept:application/json
Authorization:Bearer [token]
Content-Type:application/json
And Postman Body:
{
"request1" : "123456789",
"request2" : "2468",
"request3" : "987654321",
"name" : "John Doe"
}
Postman returns a 200, and a JSON object as a response.
Now, when I try the same with Guzzle, I get a 200 status code, but no JSON object gets returned. Here's my Guzzle implementation:
public function getClient($token)
{
return new Client([
'base_uri' => env('API_HOST'),
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json'
]);
}
$post = $client->request('POST', '/path/to/api', [
'json' => [
'request1' => 123456789,
'request2' => 2468,
'request3' => 987654321,
'name' => 'John Doe',
]
]);
Is there some trick to POSTing JSON with Guzzle? If not, is there a way to debug what's going on under the hood?
I cannot, for the life of me, understand what the difference is between the Postman POST and the Guzzle POST.
You have to use headers config sections for headers, not the root level.
return new Client([
'base_uri' => env('API_HOST'),
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
],
]);
I'm trying to make a connection with infojobs-api, the documentation explian how to make it in this way:
GET /api/1/application HTTP/1.1
Host: api.infojobs.net
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==,Bearer 07d18fac-77ea-461f-9bfe-a5e9d98deb3d
(https://developer.infojobs.net/documentation/user-oauth2/index.xhtml)
And this is my code:
$basicauth = new Client(['base_uri' => 'https://api.infojobs.net']);
$credentials = base64_encode(CLIENT_ID .':' . CLIENT_SECRET ) ;
$newresponse = $basicauth->request(
'GET',
'api/1/curriculum',
['debug' => true],
['auth' =>
['Basic', $credentials] ,
['Bearer', $acceso->access_token]
]
)->getBody()->getContents();
d($newresponse);
The API/Guzlle give me back this error:
Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: GET https://api.infojobs.net/api/1/curriculum resulted in a 401 No Autorizado response:
{"error":"102","error_description":"Client credentials not valid","timestamp":"2016-06-25T14:08:54.774Z"}
in /app/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:107
So I'm doing something wrong, but I don't find what it's wrong.
Any idea, thanks.
Oskar
As I'm seeing your request's HTTP headers:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==,Bearer 07d18fac-77ea-461f-9bfe-a5e9d98deb3d
You have an Authorization header which contains a comma separated value. They are not apart from each other. So you can't benefit from Guzzle's auth key like what you have done.
What you should do is setting Authorization header manually:
$newresponse = $basicauth->request(
'GET',
'api/1/curriculum',
['debug' => true],
['headers' =>
[
'Authorization' => "Basic {$credentials},Bearer {$acceso->access_token}"
]
]
)->getBody()->getContents();
For a post call this works for me:
$guzzle = new Client(['base_uri' => self::APIURL]);
$raw_response = $guzzle->post($endpoint, [
'headers' => [ 'Authorization' => 'Bearer ' . $publicKey ],
'body' => json_encode($data),
]);
$response = $raw_response->getBody()->getContents();