I am making an API with Laravel 5
and I'm testing it with PHPUnit
. I need to test legacy functionality for compatibility, which is an XML POST. As of right now, my first test looks like:
public function testPostMessages()
{
$response = $this->call('POST', 'xml');
$this->assertEquals(200, $response->getStatusCode());
}
This is passing just fine. Next on my list is actually sending the XML data with the POST. So for my second test, I have:
public function testPostMessagesContent()
{
$response = $this->call('POST', 'xml');
$this->assertTrue(is_valid_xml($response->getContent()));
}
This test fails. However, I am not sending my XML data. How do I send my XML?
Now, after that I need to add in the functionality to get the content from the request. I know there is a Request
object that I can interact with but I don't exactly know which method to call on it. How do I get my XML from inside my controller?
I was able to get some results in the meantime. My current test looks like this:
public function testPostMessagesContent()
{
$response = $this->call('POST', 'xml', array('key' => 'value'), array(), array(), array('content' => 'content'));
$this->assertContains('~', $response->getContent());
}
I only have the tilde there because I know it won't match so that I can see the whole response. In XmlController.php
I have:
class XmlController extends Controller {
public function index(Request $request)
{
return $request;
}
}
My output from PHPUnit
is as follows:
1) XmlTest::testPostMessagesContent
Failed asserting that 'POST xml HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Language: en-us,en;q=0.5
Content-Type: application/x-www-form-urlencoded
Host: localhost
User-Agent: Symfony/2.X
' contains "~".
Where are my parameters and my content? I feel like I am simply just using call()
incorrectly.
I updated my controller to use Request:all()
like so:
class XmlController extends Controller
{
public function index()
{
$content = Request::all();
return $content;
}
}
This returned my key-value pair, but not the content.
1) XmlTest::testPostMessagesContent
Failed asserting that '{"key":"value"}' contains "~".
Key-value pairs are good; it's progress. However, what I really need is the content since I'll be receiving that data in the content portion of the request. If I use Request::getContent()
I get back a blank string. Here's my call in the test:
$response = $this->call('POST', 'xml', array('key' => 'value'), array(), array(), array('content' => 'content'));
Here's my test results:
1) XmlTest::testPostMessagesContent
Failed asserting that '' contains "~".
I am not able to get the content body of an HTTP Request at all. Since XML wasn't working, I moved forward with the REST part of my API, which uses JSON. Here's one of my tests:
public function testPostMessagesContent()
{
$response = $this->call('POST', 'messages', ['content' => 'content']);
$this->assertEquals('saved!', $response->getContent());
}
This test passes. If I use curl, I get a successful call as well:
curl -X POST -d "content=my_new_content" "http://localhost:8000/messages"
This returns 'saved!'
That's awesome, but if I try to use curl in a standalone PHP script (to simulate a client), this is what is returned:
Array ( [url] => http://localhost:8000/messages [content_type] => text/html; charset=UTF-8 [http_code] => 302 [header_size] => 603 [request_size] => 118 [filetime] => -1 [ssl_verify_result] => 0 [redirect_count] => 0 [total_time] => 0.063977 [namelookup_time] => 0.000738 [connect_time] => 0.000866 [pretransfer_time] => 0.000943 [size_upload] => 12 [size_download] => 328 [speed_download] => 5126 [speed_upload] => 187 [download_content_length] => -1 [upload_content_length] => 12 [starttransfer_time] => 0.057606 [redirect_time] => 0 [certinfo] => Array ( ) [primary_ip] => ::1 [primary_port] => 8000 [local_ip] => ::1 [local_port] => 63248 [redirect_url] => http://localhost:8000 [request_header] => POST /messages HTTP/1.1 Host: localhost:8000 Accept: */* Content-type: text/xml Content-length: 12 ) Redirecting to http://localhost:8000.
This is my curl command adding the POST fields:
curl_setopt($ch, CURLOPT_POSTFIELDS, 'content=test');
It seems to me that POSTFIELDS is getting added to the body of the request. In this case, I still have the same problem. I am not able to get body content of my HTTP headers. After commenting out my validation, I get:
Array ( [url] => http://localhost:8000/messages [content_type] => text/html; charset=UTF-8 [http_code] => 200 [header_size] => 565 [request_size] => 118 [filetime] => -1 [ssl_verify_result] => 0 [redirect_count] => 0 [total_time] => 0.070225 [namelookup_time] => 0.000867 [connect_time] => 0.00099 [pretransfer_time] => 0.001141 [size_upload] => 12 [size_download] => 6 [speed_download] => 85 [speed_upload] => 170 [download_content_length] => -1 [upload_content_length] => 12 [starttransfer_time] => 0.065204 [redirect_time] => 0 [certinfo] => Array ( ) [primary_ip] => ::1 [primary_port] => 8000 [local_ip] => ::1 [local_port] => 63257 [redirect_url] => [request_header] => POST /messages HTTP/1.1 Host: localhost:8000 Accept: */* Content-type: text/xml Content-length: 12 ) saved!
So I have my 'saved!'
message. Great! But, in my database now I have a blank row. Not great. It is still not seeing the body content, just the headers.
I'm looking for the answers to these questions:
To retrieve the body of the POST request sent to the handler, we'll use the @RequestBody annotation, and assign its value to a String. This takes the body of the request and neatly packs it into our fullName String. We've then returned this name back, with a greeting message.
Laravel routes are located in the app/Http/routes. For instance, to pass in a name parameter to a route, it would look like this. Route::get('/params/{name}', function ($name) { return $name }); By convention, the Controller function accepts parameters based on the parameters provided.
The “path” method is used to retrieve the requested URI. The is method is used to retrieve the requested URI which matches the particular pattern specified in the argument of the method. To get the full URL, we can use the url method.
Inside controller inject Request object. So if you want to access request body inside controller method 'foo' do the following:
use Illuminate\Http\Request;
public function foo(Request $request){
$bodyContent = $request->getContent();
}
You can pass data as the third argument to call()
. Or, depending on your API, it's possible you may want to use the sixth parameter.
From the docs:
$this->call($method, $uri, $parameters, $files, $server, $content);
For those who are still getting blank response with $request->getContent()
, you can use:
$request->all()
e.g:
public function foo(Request $request){
$bodyContent = $request->all();
}
I don't think you want the data from your Request, I think you want the data from your Response. The two are different. Also you should build your response correctly in your controller.
Looking at the class in edit #2, I would make it look like this:
class XmlController extends Controller
{
public function index()
{
$content = Request::all();
return Response::json($content);
}
}
Once you've gotten that far you should check the content of your response in your test case (use print_r if necessary), you should see the data inside.
More information on Laravel responses here:
http://laravel.com/docs/5.0/responses
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With