I'm trying to send a response to an API for Oauth. Sadly, the Symfony2 docs do a poor job of explaining all the different parts of $response->headers->set(...);.
Here's my response section that's inside of my OauthController:
$response = new Response();
$response->setStatusCode(200);
$response->headers->set('Location', 'url=' . $auth_url);
return $response->send();
The controller must have a return statement so, does my code look good or how can I replicate header('Location: ' . $auth_url); from normal php?
Thanks!
Since you want to do a redirect, then you can use RedirectResponse instead of regular Response:
return new RedirectResponse($auth_url);
While #TomaszMadeyski does a good job providing you with a much better alternative, I wanted to take a minute and explain why your code does not work (as it's just fine).
The problem is that a controller much return a response, but it must not send the respond. If you look at the front controller, you'll see that it takes care of sending the response:
$response = $kernel->handle($request);
$response->send();
The reason behind this is that Symfony allows you to edit the response between the controller and the send() (e.g. to add an awesome toolbar or configure the content type).
If you're doing a redirect, shouldn't your HTTP response code be one of the codes in the 300 range to indicate a redirect?
Also, you might want to checkout this Symfony Cookbook article on redirecting.
Related
I'm trying to create a "service" like application, which can be able to receive API calls from another services. (These services will be built, for different purposes). And also able to send API calls to an another one.
Each request that they send, and accept has to have the following format.
{
header : {
// some header information, like locale, currency code etc.
signature : "some-hashed-data-using-the-whole-request"
},
request : {
// the usable business data
}
}
To each request I want to append a hash, that is generated from the actual request or anyhow (salted with password or any kind of magic added). Its not that important at the moment. I gave the name signature to this field. So for each received request, I want to reproduce this signature from the request. If the signature I received is matching with the one I generated, I let the application run otherwise showing some error message.
I already read a few articles, but most of them is for user-pass combinations.
My question is not about that if it's a good solution or not. I just want to know how can implement a middleware like functionality - like in laravel - in Symfony 4?
Instead of putting headers into a JSON object the HTTP body, use HTTP headers directly. That’s what they are for. When you’re using non-standard headers, prefix them with X- and maybe a prefix for your application, for example X-YourApp-Signature. The request goes into the body, i.e. the value of the request property in your example.
The server side is pretty simple with Symfony:
public function someAction(Request $request)
{
$signature = $request->headers->get("X-YourApp-Signature");
$data = json_decode($request->getContent());
// ... go on processing the received values (validation etc.)
}
If you want to write a HTTP client application in PHP, I would recommend using the Guzzle library. Here’s an example:
$headers = ["X-YourApp-Signature" => "your_signature_string"];
$data = json_encode(["foo" => "bar"]);
$request = new \GuzzleHttp\Psr7\Request("POST", "https://example.com", $headers, $data);
$client = new \GuzzleHttp\Client();
$response = $client->send($request, ["timeout" => 10]);
var_dump($response);
Of course, you’ll also want to implement some error handling etc. (HTTP status >= 400), so the code will be a bit more complex in a real application.
As k0pernikus mentioned, the before after filters solves my issue.
I'm building an api at my company using laravel.
The problem I'm encountering is that if you send an api request without defining the correct header with the request you will get html back if there is a failure e.g. authorization failure or findOrFail() failure.
My thinking is that you never want to return html (even if the user has the wrong header).
I have a couple of solutions. In BeforeMiddleware.php I can manually insert a header into the request such as:
// Check if we are on an api route
$apiRoute = strncmp($uri, '/api/', 5) == 0;
// Insert the request header to force json response
if ($apiRoute){
$language = $request->header->add('Accept', 'application/json');
}
The 2nd solutions would be to throw an error if they don't have the correct header.
What would be the best way to enforce a json response, what is a good practice for handling api responses in laravel?
Once you detected that you are on your api path you are out of the woods and can indeed tackle your problem in the app\Exceptions\Handler.php file like suggested on How do you force a JSON response on every response in Laravel?.
For an open source project I created JSON exception objects by Microsoft format as output, but you can choose the jsonapi format (http://jsonapi.org/examples/#error-objects-basics) as you like:
https://github.com/StadGent/laravel_site_opening-hours/blob/develop/app/Exceptions/Handler.php
(note that on this implementation it is indeed depending from the headers, but you can use your path detection I think)
In the book of laravel I read, and also my co-worker who has experience with laravel said that generating JSON I should in laravel way.
Why do I need to do this:
Route::get('markdown/response', function()
{
$data = array('iron', 'man', 'rocks');
return Response::json($data);
});
As I read it sends also content-type header when using this.
When I was using codeigniter I used to do simply this:
echo json_endode($data);
and never ever ever had any problems. Even if it is not set content type. Actually I dont know maybe php sets it automatically, but since I did not have problems, I did not care.
And when using 'new' technology I really want to know why it is better than good old one.
With respect, by not providing a content-type header, you were doing it "wrong" when coding in CodeIgniter.
Most clients (browsers, ajax requests, especially jQuery) can still can guess how to handle the response correctly and so probably "just worked" for you. You were likely always implicitly returning a Content-Type: text/html with your response, which is a default header in CodeIgniter.
You should always return a proper content type with your HTTP responses so the consuming client knows how to treat this content. Note that this is a mechanism of HTTP as defined in specification, not specific to any framework or even a language.
Response::json()
The above code is just a convenience function, where Laravel will automatically set the application/json header for you, as well as convert an array of data into JSON format. The only effective difference from your CodeIgniter code is the setting of the header, as you've pointed out.
It's worth noting that the Response object extends Symfony's response object, which is very "powerful" - in other words, it's a very good implementation of the HTTP protocol.
The response object returned from Response::json (and other Response static methods) are highly modifiable.
$response = Response::json($data);
$response->header('Content-Type', 'application/json');
return $response;
You can check for more available methods in the Laravel and Symfony code API.
http://laravel.com/api/class-Illuminate.Http.Response.html
http://api.symfony.com/2.1/Symfony/Component/HttpFoundation/Response.html
Just because it worked doesn't mean it wasn't wrong. JSON isn't HTML, so text/html is an inaccurate Content-Type for it.
Sending the correct header means libraries like jQuery understand what sort of data they're getting back, and thus are able to handle it on their own without guidance. Browsers may also do things like pretty-printing the JSON data or making it otherwise easier to read.
Depends what you are trying to do with the route. if you only want to return json data you can just return json_encode($data) and that will work, To actually return a json response for use with something like an ajax request you need the headers set properly or the accepting route just thinks its getting a string. Response::json is for setting the response which sets the headers appropriately.
I'm trying to get a JSON string from a page in my Laravel Project. Using this:
$json = file_get_contents($url);
$data = json_decode($json, TRUE);
return View::make('adventuretime.marceline')
->with('json', $json)
->with('title', 'ICE KING')
->with('description', 'I am the Ice King')
->with('content', 'ice king');
But since I'm only using a localhost, I think this doesn't work that's why it doesn't output anything. I want to know what is the proper way for it to be flexible and be able to get the JSON string with any $url value using php?
Looking at the comments above, it is possible that the $url you are using is not valid, check it out by pointing your browser there and see what happens.
If you are sure that the $url is fine, but you still get the 404 Not Found error - verify that you have proper Laravel routing defined for that address. If the routes are fine, maybe you forgot to do
composer dump-autoload
after making modifications in your routes.php. If so, try the above and refresh the browser to see if it helps.
Furthermore, bear in mind that using your current function, you can submit only GET requests. What is more, this function might not be available for fetching remote urls, on some hosting servers due to security reasons. If you still want to use it, it'd be good to check
if($json !== FALSE)
before you process the $json response. If the file_get_contents fails it will return false.
Reffering to the part of your question
what is the proper way for it to be flexible and be able to get the JSON string with any $url
I'd suggest using cURL, as a standard and convenient way to fetch remote content. Using cURL you have better control over the process of sending the http request and receiving the "answer" it returns. Personaly, in my Laravel 4 apps I often use this package jyggen/curl. You can read the docs for it here: jyggen docs
If you are not satisfied with cURL and you want greater control try Guzzle As the authors state, Guzzle is a PHP HTTP client & framework for building RESTful web service clients.
I used Zend Framework 1.11 to make a REST web service in PHP using the Zend_Rest_server class but I wasn't able to intercept and analyze the responses from Zend_Rest_server instances before these are sent to the clients.
To make the REST web service I use this snippet of code:
$server = new Zend_Rest_Server();
$server->setClass('Ws_dummy', 'dummy');
$server->handle();
Is there a method to log responses because I need to analyze them and I wasn't able to find a way to solve this need.
Thank you in advance for any help you can provide.
P.S. For example in SOAP web services I can do this:
$server->setReturnResponse(true);
$response = $server->handle();
or
$server->handle();
$response = $server->getLastResponse();
and analyze the responses
You can log Requests like this:
$writer = new Zend_Log_Writer_Stream('/path/to/logfile');
$logger = new Zend_Log($writer);
$logger->info( Zend_Debug::dump( $_REQUEST, 'Request-Dump', false );
You should do that before the Rest_Server handles the Request.
If you got further Questions - just ask :-)
Edit (added some useful information):
It may be helpful to understand that Zend_Debug::dump() method wraps the PHP function var_dump(). If the output stream is detected as a web presentation, the output of var_dump() is escaped using htmlspecialchars() and wrapped with (X)HTML pre-tags.
Edit #2:
You can return the Response of Zend_Rest_Server with:
$server->returnResponse(true);
before $server->handle().
Edit #3:
Be aware:
If I've read everything right you need to send the Headers by urself if you are returning the Response.
You can get/+set the Headers with:
$headers = $server->getHeaders();
foreach( $headers as $header ) header( $header );