I have this SOAP request done in nodejs and it's working fine:
await soap
.createClientAsync(wsdlURL)
.then(async instance => {
const wsseopts = {
passwordType,
hasNonce: true,
hasTimeStamp: false
};
const wsse = new soap.WSSecurity(user, pass, wsseopts);
instance.setSecurity(wsse);
client = instance;
})
.then(async () => {
return await client
.getFunction({
token
})
.then(async response => {
const data = await client.getFunctionSecond({
token,
param1,
param2
});
});
})
.catch(err => {
console.warn(err);
return false;
});
I tried doing this in Laravel but the API returns an error, it let's me connect with the SOAPClient but it fails when trying to execute the "getFunction"
$options = [
'login' => $login,
'password' => $password,
'authentication' => $authentication,
'trace' => true
];
$wsseopts = array(
'passwordType' => 'PasswordText',
'hasNonce' => true,
'hasTimeStamp' => false
);
$wsse = new SoapHeader('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', 'Security', $wsseopts, false);
$client = new SoapClient($url, $options);
$client->__setSoapHeaders($wsse);
$response = $client->getFunction([ //IT CRASHES HERE
'token' => $token
]);
$response2 = $client->getFunctionSecond([
...
]);
Maybe it's something related to the headers, I was unclear about how to set them as it is in Nodejs, but I didn't find the solution.
Related
I have created a function that contacts a remote API using Guzzle but I cannot get it to return all of the data available.
I call the function here:
$arr = array(
'skip' => 0,
'take' => 1000,
);
$sims = api_request('sims', $arr);
And here is the function, where I have tried the following in my $response variable
json_decode($x->getBody(), true)
json_decode($x->getBody()->getContents(), true)
But neither has shown any more records. It returns 10 records, and I know there are over 51 available that it should be returning.
use GuzzleHttp\Client;
function api_request($url, $vars = array(), $type = 'GET') {
$username = '***';
$password = '***';
//use GuzzleHttp\Client;
$client = new Client([
'auth' => [$username, $password],
]);
$auth_header = 'Basic '.$username.':'.$password;
$headers = ['Authorization' => $auth_header, 'Content-Type' => 'application/json'];
$json_data = json_encode($vars);
$end_point = 'https://simportal-api.azurewebsites.net/api/v1/';
try {
$x = $client->request($type, $end_point.$url, ['headers' => $headers, 'body' => $json_data]);
$response = array(
'success' => true,
'response' => // SEE ABOVE //
);
} catch (GuzzleHttp\Exception\ClientException $e) {
$response = array(
'success' => false,
'errors' => json_decode($e->getResponse()->getBody(true)),
);
}
return $response;
}
By reading the documentation on https://simportal-api.azurewebsites.net/Help/Api/GET-api-v1-sims_search_skip_take I assume that the server is not accepting your parameters in the body of that GET request and assuming the default of 10, as it is normal in many applications, get requests tend to only use query string parameters.
In that function I'd try to change it in order to send a body in case of a POST/PUT/PATCH request, and a "query" without json_encode in case of a GET/DELETE request. Example from guzzle documentation:
$client->request('GET', 'http://httpbin.org', [
'query' => ['foo' => 'bar']
]);
Source: https://docs.guzzlephp.org/en/stable/quickstart.html#query-string-parameters
I have a php class that uses guzzle to call an API and get a response:
public function getResponseToken()
{
$response = $this->myGUzzleClient->request(
'POST',
'/token.php,
[
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded'
],
'form_params' => [
'username' => $this->params['username'],
'password' => $this->params['password'],
]
]
);
return json_decode($response->getBody()->getContents())->token;
}
I am trying to test this method using guzzle mock handler, this is what I have done so far but not working:
public function testGetResponseToken()
{
$token = 'stringtoken12345stringtoken12345stringtoken12345';
$mockHandler = new MockHandler([
new Response(200, ['X-Foo' => 'Bar'], $token)
]
);
$handlerStack = HandlerStack::create($mockHandler);
$client = new Client(['handler' => $handlerStack]);
$myService = new MyService(
new Logger('testLogger'),
$client,
$this->config
);
$this->assertEquals($token, $myService->getResponseToken());
}
the error I am getting says "Trying to get property of non-object", so looks to me MyService is not using the handler to make the call. What am I doing wrong?
The class works as expected outside of the test context. Also note the client in normally injected in MyService from service.yml (I am using symfony).
Your handler work fine, you just mock the wrong response data. You should make the response as raw json.
Try
$token = 'stringtoken12345stringtoken12345stringtoken12345';
$mockHandler = new MockHandler(
[
new Response(200, ['X-Foo' => 'Bar'], \json_encode([ 'token' => $token ]))
]
);
Now it should be works
I tried to convert an AJAX API request script into php using Guzzle, however I keep getting a '400 Bad Request' error. The Ajax version works fine.But I'm trying to automate the process in the back end. The script sends a file to the remote API via a 'POST' request and is meant to return a JSON object back which I then save it to a file.
Most of the possible solutions I found(googled for) involved either doing some exception handling or straight deactivating the guzzle errors. None of which worked. I know that the credentials are all correct because I tested with wrong credentials and it returned an authorization error.
This AJAX code works fine, it gets a file from an html form and uploads it to the API server.
$('#btnUploadFile').on('click', function () {
var data = new FormData();
var files = $("#fileUpload").get(0).files;
for (var i = 0; i < files.length; i++) {
data.append("audioFiles", files[i]); }
data.append("scoresTypes", JSON.stringify([46, 47]));
data.append("Flavor", 1);
data.append("AgentUsername", 'person#email.com');
var ajaxRequest = $.ajax({ type: "POST", url: 'https://remoteserver.com/api/',
headers: { 'Authorization': 'Basic ' + btoa('username' + ':' + 'password') },
scoresTypes: "",
contentType: false,
processData: false,
data: data,
success: function (data) { $("#response").html(JSON.stringify(data)); } });
ajaxRequest.done(function (xhr, textStatus) { });
});
});
This is the PHP code that returns the error '400 Bad Request' to the file
public function sendFile($file_path, $file_name){
$client = new Client();
$url = 'https://remoteserver.com/api/';
$credentials = base64_encode('username:password');
$audio = fopen($file_path, 'r');
$data = [];
$data['audioFiles'] = $audio;
$data['scoresTypes'] = json_encode([46, 47]);
$data['Flavor'] = 1;
$data['AgentUsername'] = 'person#email.com';
$json_file = '/path/'.$file_name.'.json';
try{
$response = $client->request('POST', $url, [
'headers' => [
'Authorization' => 'Basic '.$credentials,
],
'scoresTypes' => '',
'contentType' => 'false',
'processData' => false,
'data'=>$data
]);
$response_s = json_encode($response);
}
catch(RequestException $e) {
$response_s = $e->getResponse()->getBody();
}
Storage::disk('disk_name')->put($json_file, $response_s);
So this is the output that the PHP function is saving to the file instead of the expected JSON object.
{"code":14,"message":"There are no values in scoresTypes or JobTypes keys, please insert valid values in one, or both of them.","responseStatusCode":400}
But as you can see the initial data provided to the ajax version seems to be the same as the one I send in the php request.
have you tried setting the Content-Type to multipart/form-data since you are sending files, i think the default header for post request is application/x-www-form-urlencoded
I'm not a guzzle expert but from what i saw on the examples here you can use something like this instead
http://docs.guzzlephp.org/en/latest/quickstart.html?highlight=file#sending-form-files
<?php
$response = $client->request('POST', 'http://httpbin.org/post', [
'multipart' => [
[
'name' => 'field_name',
'contents' => 'abc'
],
[
'name' => 'file_name',
'contents' => fopen('/path/to/file', 'r')
],
[
'name' => 'other_file',
'contents' => 'hello',
'filename' => 'filename.txt',
'headers' => [
'X-Foo' => 'this is an extra header to include'
]
]
]
]);
I have some problem with my guzzle client. I set timeout for example 1.0 and in some route I do sleep(5). Guzzle anyway wait on response when should just throw exception.
client:
$requests[] = new Request('GET', $path, [
'timeout' => 1,
'connect_timeout' => 1
]);
$pool = new Pool($this->client, $requests, [
'concurrency' => 5,
'fulfilled' => function ($response, $index) use ($response_merger) {
$response_merger->fulfilled($response);
},
'rejected' => function ($reason, $index) use ($response_merger) {
$response_merger->error($reason);
}
]);
and my route with delay:
$app->get('/timeout', function() use ($app) {
sleep(5);
return (new JsonResponse())->setData([ 'error' => 'My timeout exception.' ])->setStatusCode(504);
});
I always get 504 with My timeout exception, when I should not get it because timeout is set.
I did it with set client, but it is not a solution for me because I need custom timeout for certain request, not client.
$this->client = new Client([
'timeout' => 3.0,
'connect_timeout' => 1.0
]);
I think you've got the wrong signature in mind for new Request(). From the docs:
// Create a PSR-7 request object to send
$headers = ['X-Foo' => 'Bar'];
$body = 'Hello!';
$request = new Request('HEAD', 'http://httpbin.org/head', $headers, $body);
The third parameter is for HTTP headers, not options.
You should pass timeout as an option when constructing the Pool:
$pool = new Pool($this->client, $requests, [
'concurrency' => 5,
'options' => ['timeout' => 10],
'fulfilled' => function ($response, $index) use ($response_merger) {
$response_merger->fulfilled($response);
},
'rejected' => function ($reason, $index) use ($response_merger) {
$response_merger->error($reason);
}
]);
Found this in comments of the Pool code here.
I started with AWS Lambda today and I can't succeed in passing a payload to the function. On the server side I try to read all the event data but it is empty. What am I doing wrong here?
$client = LambdaClient::factory(array(
'profile' => 'default',
'key' => AWS_ACCESS_KEY_ID,
'secret' => AWS_SECRET_ACCESS_KEY,
'region' => 'eu-west-1'
));
$payload = array('key1' => '1');
$result = $client->invoke(array(
'FunctionName' => 'hello',
'InvocationType' => 'RequestResponse',
'LogType' => 'Tail',
'Payload' => json_encode($payload)
));
Returns:
Received event: {}
Function code on AWS:
console.log('Loading function');
exports.handler = function(event, context) {
console.log('Received event:', JSON.stringify(event, null, 2));
};
In python I send the payload like this:
from boto3 import client as botoClient
import json
lambdas = botoClient("lambda")
def lambda_handler(event, context):
response = lambdas.invoke(FunctionName="myLambdaFunct", InvocationType="RequestResponse", Payload=json.dumps(event));
where event is a dictionary and, json.dumps serialize event to a JSON formatted string