I have a generic HTTP file access API which I use for the system I'm working on. To make it as flexible as possible, it returns request and response data in the form of HTTP strings.
I'm currently implementing a version which interacts with the S3, via the AWS SDK for PHP 2.
Is there an easy way to quickly get the Request and Response HTTP requests which the S3Client makes when performing operations? If not, is there a more piecemeal way which I can use to not have to fake it?
Basically, I'd like the full-text of both the Request and Response on demand, or at least access to relevant data (headers, response codes, URLs, etc) so I can properly populate the return data for my framework.
Thanks.
You can get either the request or response object from a command object. Assuming $s3 holds an instance of Aws\S3\S3Client, you could do something like this:
$command = $s3->getCommand('ListObjects', array('Bucket' => '<bucket-name>'));
$request = $command->getRequest();
$response = $command->getResponse();
Those objects have methods for viewing the body, headers, status codes, etc. and you can cast them to string to see the string form.
If you want to quickly see the request and response as you are executing commands, you can attach the wire logger, and see what comes out on STDOUT (or STDERR)
$s3->addSubscriber(\Guzzle\Plugin\Log\LogPlugin::getDebugPlugin());
$s3->listObjects(array('Bucket' => '<bucket-name>'));
You will need to look into the Guzzle\Http\Client class, which is an ancestor class to S3Client, to have a look at the methods that it makes available. You can always override some of these methods in your own child of S3Client to make accessing this information easier for you.
Ultimately the data you are looking for resides in an object of class Guzzle\Http\Message\Response, which I believe is returned from Guzzle\Http\Client::send().
So perhaps in your own implementation of S3Client you can override the send() method to send the HTTP requests, then process the response data as needed.
Related
I am trying to send a SOAP request to a client's API endpoint. I am not at all familiar with SOAP, so having quite a difficult time getting this to work.
From the client's documentation
The requested ticket can be used to call all the API web methods subsequently.
public string RequestTicket(
string username,
string password
);
URL
https://www.clientsurl.net/api/v01_00/APIService.asmx?wsdl
Parameters
string username
string password
I am able to create the WSDL
$client = new Client('https://www.clientsurl.ca/api/v01_00/APIService.asmx?wsdl', ['soap_version' => SOAP_1_1]);
but not sure how to send the parameters through
$params = [
'username' => 'myusername'
'password' => 'mypassword'
];
I am also not sure what the relevance of RequestTicket is. Am I supposed to add it to the url?
The answer is probably very simple, but after tons of searching I couldn't find anything. Please help.
I have write a method to send a request
protected function soapRequest(string $method, array $arguments)
{
try {
$client = new \Zend\Soap\Client($this->getWsdl(),
[
'soap_version' => SOAP_1_1,
'cache_wsdl' => WSDL_CACHE_NONE
]);
$result = $client->{$method}($arguments);
return $result->return;
} catch (\SoapFault $s) {
...
} catch (\Exception $e) {
...
}
}
You must have a Soap method to send yours parameters.
If you don't know the method name, I advise you to run SoapUI application, very useful for debugging soap requests.
A SOAP service has a set of operations that you can call over the network. These operations can also have parameters. Basically, it's just like calling a method with parameters in code just that the invocation happens over the network with the method name and parameters being marshaled into an XML that respects the rules of the SOAP protocol.
To call the SOAP service, you can either make a HTTP request of type POST to the service's endpoint (i.e. https://www.clientsurl.ca/api/v01_00/APIService.asmx) or you can use a SOAP client. A SOAP client is some code that you can generate from the WSDL of the SOAP web service, or is some code that can dynamically read the WSDL and provide you some ways to invoke the operations described there. As opposed to making a POST HTTP request, the client takes care of these details for you and allows you to make the call over the network just like you call a local method in your code.
To call an operation of the SOAP service in your client code you have to invoke a method with parameters. The name of the method and its parameters (what names and what types) are described by the WSDL of the service.
With that being said, I'll add some details about what you posted in your question.
The requested ticket can be used to call all the API web methods subsequently.
Some service operations can require authentication in order to be be allowed to invoke them. Just like you need a username and password to access protected sections of a website for example. For a SOAP web service, his can happen in a few ways, the most common two being:
you send the username and password with each call to the web service (somehow; can be as SOAP headers, as HTTP headers with BASIC Authentication, etc).
the service exposes a method that you have to call with username and password just like point 1), but then returns an access token of some sort that you then need to provide to the rest of the web service's operations. This is just like a Login page on a website where you authenticate with username and password and then you get back a SessionID that you can use on all other requests until you decide to log out.
It seems that your service uses the second approach, and RequestTicket seems to be the operation that you need to call in order to be able to call the rest of the operations after that.
I am able to create the WSDL
You do not create the WSDL, the WSDL already exists for the web service. Also make sure you do not make a confusion between the SOAP web service and its WSDL. The code you show just creates a SOAP client from the WSDL (what I described above) to allow you to invoke operations on it.
I am also not sure what the relevance of RequestTicket is. Am I supposed to add it to the url?
Most likely RequestTicket is an operation of the web service. You should look inside the WSDL to see if it's described there. The WSDL is a little tough to swallow if you are not familiar with how it works, so your best bet is to use a tool like SoapUI to feed it the web service WSDL and have SoapUI generate sample requests for the web service. You can then also use SoapUI to test the web service to make sure you understand how it works before you try to replicate the same calls with your PHP code.
So i have found on the Api from Amazon that you can start and stop the instance with this
$result = $client->startInstances([/* ... */]);
and also like this
$promise = $client->startInstances([/* ... */]);
So here is my question. Are there any diffrences between the $promise and the $result.
From the PHP SDK for EC2 documentation page that you linked in your Question:
Each of the following operations can be created from a client using $client->getCommand('CommandName'), where "CommandName" is the name of one of the following operations. Note: a command is a value that encapsulates an operation and the parameters used to create an HTTP request.
You can also create and send a command immediately using the magic methods available on a client object: $client->commandName(/* parameters */). You can send the command asynchronously (returning a promise) by appending the word "Async" to the operation name: $client->commandNameAsync(/* parameters */).
I am currently busy with a PSR-7 project with responses and requests.
Currently we are setting up an application in our index.php by doing something like:
$app = new Application();
$app->loadConfiguration(
'../config/global.yml',
);
// Should return the response?
$app->run((new ServerRequestFactory())->createServerRequestFromGlobals());
Here the run method also calls an emit method that is responsible for sending the headers and printing the body of the response.
The request and respons are now linked together in one call which makes it hard to test since you don't want to send the response with the headers straight to PHPUnit.
I have removed the emit call in the chain of the run method and added this to the index after the run method call:
// Send the response.
$app->send();
This way they are decoupled but the downside is I now have to hold a instance of my response in a response property inside my Application.php($app) class.
I want to move the response instance to the response class itself but my co-workers thinks a class should never hold an instance of itself. Yet when I look at frameworks this happens quite a lot. Is he right about this?
What arguments can I make to decouple my request and response besides easier testing?
I am pretty new to unit testing, one of the arguments I have already heard is that I should not test the full application anyways but rather separate components and therefore should not be worried about de-coupling the request and response.
How do I unit test for my code which makes http requests . Instead of making actual http call, I want to use mock objects and verify http request has has correct body and headers set.
Your description doesn't contain a lot of information. But for the start I can guide you using this example code.
$httpMock = $this->getMockBuilder('\Vendor\Path\HttpHandlerYouWantToMock')
->disableOriginalConstructor()
->setMethods(['setBody', 'setHeader'])
->getMock();
$httpMock->expects($this->once())
->method('setBody')
->with($this->identicalTo('{"test":"test"}'));
$httpMock->expects($this->once())
->method('setHeader')
->with($this->identicalTo('Content-Type: application/json'));
$service = new SomeService($httpMock);
$service->post('/someApi', '{"test":"test"}');
This code just in a representation how all should look like but in your case I have no idea what http handler are you using or if this one contain any other services that is dependent on.
So main idea just mock all your services that are used by your own service. And define for this mock what methods you think will be used an what data should be passed there.
And the last use the phpunit documentation https://phpunit.de/manual/current/en/test-doubles.html
I used a downloaded tool to auto-create a wrapper for a web service (fedex rate service) as it creates a really handy code base for accessing the service that auto-generates a class map and builds an auto-loading data structure by asking the web service itself for it's requirements and capabilities. It creates this wrapper as an 'extend' of SoapClient itself.
The only problem is, that it makes the separate service calls using an abstract wrapper that utilizes the __soapCall method. The problem that I've noticed with this is that it apparently doesn't populate anything where you can retrieve the XML from the calls themselves. Whenever I call __getLastRequest or __getLastResponse, they just return null even though __soapCall('getRates', $args) returns a php object response from the service.
Short of my re-writing the auto-generated code to call $this->getRates($args) or something similar, is there any trick to seeing the XML used in the request and returned in the response when using __soapCall ?
Nevermind - I thought I had trace defaulted to true, and the reason i was getting back 'null' was that it was defaulting to false.
As long as I create the interface instance with the second argument array('trace'=>1) I'm getting the XML now.