I'm new to laravel, and I'm trying to implement a simple rest api.
I have the controller implemented, and tested via unit testing.
My problem is with the POST request.
Via the tests Input:json has data, via an external rest client it returns null.
This is the code on the unit test
$newMenu = array(
'name'=>'Christmas Menu',
'description'=>'Christmas Menu',
'img_url'=>'http://www.example.com',
'type_id'=>1,
);
Request::setMethod('POST');
Input::$json = $newMenu;
$response = Controller::call('menu#index');
What am I doing wrong?
UPDATE:
This is realy driving me crazy
I've instanciated a new laravel project and just have this code:
Routes
Route::get('test', 'home#index');
Route::post('test', 'home#index');
Controller:
class Home_Controller extends Base_Controller {
public $restful = true;
public function get_index()
{
return Response::json(['test'=>'hello world']);
}
public function post_index()
{
return Response::json(['test'=>Input::all()]);
}
}
CURL call:
curl -H "Accept:application/json" -H"Content-type: application/json" -X POST -d '{"title":"world"}' http://localhost/laravel-post/public/test
response:
{"test":[]}
Can anyone point me to what is wrong.
This is really preventing me to use laravel, and I really liked the concept.
Because you are posting JSON as your HTTP body you don't get it with Input::all();
You should use:
$postInput = file_get_contents('php://input');
$data = json_decode($postInput, true);
$response = array('test' => $data);
return Response::json($response);
Also you can use
Route::any('test', 'home#index');
instead of
Route::get('test', 'home#index');
Route::post('test', 'home#index');
Remove header Content-type: application/json if you are sending it as key value pairs and not a json
If you use : Route::post('test', 'XYZController#test');
Send data format : Content-type : application/json
For example : {"data":"foo bar"}
And you can get the post (any others:get, put...etc) data with :
Input::get('data');
This is clearly written in here : http://laravel.com/docs/requests
. Correct Content-type is very important!
I am not sure your CURL call is correct. Maybe this can be helpful : How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?
I am using Input::get('data') and it works.
I was facing this problem, my response of post was always null. To solve that I put the body key in guzzle object, like this
$client = new Client([
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => config('app.callisto_token'),
]
]);
$body = [
'firstResult'=> 0,
'data' => '05/05/2022'
];
$response = $client->post('http://'.$this->ip.'/IntegracaoERP'.'/status_pedido',
['body' => json_encode($body)]
);
Don't forget the json_encode in body key.
Hope this helps.
Related
I am trying to send a POST request using Guzzle to a route defined in my routes/web.php from a model. Both the model and the controller are defined in the same Laravel application. The controller action linked to the route returns a JSON response and works fine when called from javascript using Ajax. However, when I try to do this using Guzzle, I have the following error:
GuzzleHttp \ Exception \ ClientException (419)
Client error: `POST https://dev.application.com/login` resulted in a `419 unknown status` response
When searching for a solution, I read that it may be caused by a missing csrf token, so I added it to my reuqest, but I still get the same error.
Here's the model code that uses Guzzle to send the request:
$client = new Client();
$response = $client->post(APPLICATION_URL.'login', [
'headers' => [
'X-CSRF-Token' => csrf_token()
],
'form_params' => [
'socialNetwork' => 'L',
'id_token' => $id
],
]);
APPLICATION_URL is simply the base URL of the application, starting with https://.
Am I missing something? Thanks in advance!
Don't send requests internally in your app, forward the call by dispatching post requests to routes instead
This method seems faster than using an HTTP client library like Guzzle
Your code should look something like this
$request = Request::create(APPLICATION_URL . 'login', 'POST', [
'socialNetwork' => 'L',
'id_token' => $id
]);
$request->headers->set('X-CSRF-TOKEN', csrf_token());
$response = app()->handle($request);
$response = json_decode($response->getContent(), true);
Update
You have to manually handle the response from internally dispatched routes, here's an example to get started
web.php
use Illuminate\Http\Request;
Route::get('/', function () {
$request = Request::create('/test', 'POST', ['var' => 'bar']);
$request->headers->set('X-CSRF-TOKEN', csrf_token());
$response = app()->handle($request);
$responseContent = json_decode($response->getContent(), true);
return $responseContent;
});
Route::post('test', function () {
$upperCaseVar = strtoupper(request()->var);
return response(['foo' => $upperCaseVar]);
});
Access / route by GET request and get response from /test as if it's POST request
Result
{
"foo": "BAR"
}
Hope this helps
i am using guzzle to post some data to some api and recive some data back here is my code :
$response = $client->request('POST', 'http://url/api/v1/transaction/Verify', [
'headers' => ['Content-Type' => 'application/json'],
'body' => '{
"tn":"1905463527",
}'
]);
$responebody = $response->getBody();
i exacly dont know if i am getting string or object when ever i use getbody of guzzle but here is what i get when i echo the response :
{"errorCode":null,"errorMessage":"Canceled by user.","succeed":false,"tn":1905463527,"verifyCount":35,"amount":10000}
now here for example i want to access the "succeed " element and i want to know how can i access to check if it is true or not ,
You should check the Content-Type header and if it's application/json you can run json_decode on the body. Take this as an example
if ($response->getContentType() == 'application/json') {
$responseBody = json_decode($response->getContent());
// now you can access $responseBody->succeed
...
}
I am using guzzle for getting post of a single page and it is working fine. But now the problem is page has pagination 20 post on each page. i want to get all the posts. How can I do it by using guzzle ?
here is my code:
public function __construct()
{
$this->client = new Client([
'base_uri' => 'https://xxxxxx.com/',
'Content-Type' => 'application/json',
]);
}
public function post($post)
{
$response = $this->client->request('GET', $post);
$output = $response->getBody()->getContents();
$data = $this->getData($output);
return $data;
}
There is no way to do it in general. HTTP as a protocol doesn't specify anything about pagination. So depends on the server you work with. Usually the response contains something like
{
"page": 5,
"total": 631
}
Based on this info you can create an URL for the next page by adding ?page=6 (also depends on the server) and request it.
I am trying to post a form via cURL from inside a zend framework 2 console route.
I am doing something like
php public/index.php myroute
To call the route from terminal. Inside that route is the following:
$request = new \Zend\Http\Request;
$request->setMethod('POST');
$request->setUri('http://somesite.com');
$request->getHeaders()->addHeaders([
'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8'
]);
/* set post fields */
$aData = array('hello' => 'world');
$request->setContent($request->getPost()->toString());
/* just to look at request string in console */
echo $request->toString()."\n";
/* post the data */
$client = new \Zend\Http\Client;
$client->setAdapter("Zend\Http\Client\Adapter\Curl");
$response = $client->dispatch($request);
Problem is that this throws a cookie exception when ran from console:
POST http://somesite.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
hello=world
======================================================================
The application has thrown an exception!
======================================================================
Zend\Http\Header\Exception\InvalidArgumentException
Cookie name cannot contain these characters: =,; \t\r\n\013\014 (WEBUK=)
If anyone can point out how to get around this I would be very grateful.
The code works in a normal route OKAY...it only complains about the cookie issue when I run it from console.
Fixed my issue for now. I have decided to give up on using zf2 methods for this and instead just use Guzzle.
$aData = array('hello' => 'world');
$httpClient = new GuzzleHttp();
$r = $httpClient->post('http://somesite.com', [
'body' => $aData
]);
$response = $httpClient->send($r);
I have seen many examples on how to set headers on a response but I cannot find a way to inspect the headers of a response.
For example in a test case I have:
public function testGetJson()
{
$response = $this->action('GET', 'LocationTypeController#index', null, array('Accept' => 'application/json'));
$this->assertResponseStatus(200);
//some code here to test that the response content-type is 'application/json'
}
public function testGetXml()
{
$response = $this->action('GET', 'LocationTypeController#index', null, array('Accept' => 'text/xml'));
$this->assertResponseStatus(200);
//some code here to test that the response content-type is 'text/xml'
}
How would I go about testing that the content-type header is 'application/json' or any other content-type? Maybe I'm misunderstanding something?
The controllers I have can do content negation with the Accept header and I want to make sure the content type in the response is correct.
Thanks!
After some digging around in the Symfony and Laravel docs I was able to figure it out...
public function testGetJson()
{
// Symfony interally prefixes headers with "HTTP", so
// just Accept would not work. I also had the method signature wrong...
$response = $this->action('GET', 'LocationTypeController#index',
array(), array(), array(), array('HTTP_Accept' => 'application/json'));
$this->assertResponseStatus(200);
// I just needed to access the public
// headers var (which is a Symfony ResponseHeaderBag object)
$this->assertEquals('application/json',
$response->headers->get('Content-Type'));
}
While not specifically about testing, a nice way of getting at Laravel's response object is to register a 'Finish' callback. These are executed just after the response is delivered, right before the app closes. The callback receives the request and the response objects as arguments.
App::finish(function($request, $response) {
if (Str::contains($response->headers->get('content-type'), 'text/xml') {
// Response is XML
}
}
Take a look at the laravel documentation
Request::header('accept'); // or
Response::header('accept');
Retrieving A Request Header
$value = Request::header('Content-Type');
Another way would be to use getallheaders() :
var_dump(getallheaders());
// array(8) {
// ["Accept"]=>
// string(63) "text/html[...]"
// ["Accept-Charset"]=> ...
For debugging purposes You could simply use this:
var_dump($response->headers);