I'm writing an API in Cake2.1.3 using the REST instructions in the docs. Having previously written one in Cake1.3, I would use the now-deprecated cakeError class to issue a response with an HTTP code in the format it was requested in. For example, if I requested http://example.com/widgets/view/invalid-code.json, cakeError would dispatch a 400 error code (and message) in the JSON format. Cake 2.x uses exceptions to handle this. According to the docs:
throw new BadRequestException()
issues a 400 HTTP code with a "Bad Request" message, but it only seems to do so in the HTML format. Can it automatically respond in the format it was requested in?
While you can do it with the selected answer, an easier way would be to let Cake render it automatically. Cake uses the same view finding rules when rendering exceptions. This means simply add a 'json' folder to the Error folder in your view, and create the appropriate view file.
/View
/Errors
/json
error404.ctp
error404.ctp
The error view could be something simple, like this:
<?php
echo json_encode(array(
'error' => array(
'name' => $name,
'url' => $url
)
));
Visiting /users/missing-page.json will then render the following json:
{"code":404,"url":"\/users\/missing-page.json","name":"Action UsersController::missing-page() could not be found."}
From my knowledge there's no way to do this automatically, but you could write your own exception handler that checks the request and outputs the appropriate content type.
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)
right now I'm building a project with the laravel framework. I'm not a professional or whatever, in the past I built all my applications from scratch without the use of such frameworks.
Right now I'm implenting the Twitch API for certain parts of my website. While doing that I encoutered situations where the Twitch API returns an http error code (40x) even though it provides a "valid" response. Right now I'm using a pretty popular Twitch API package from packagist.org. As soon as I receive an 40x error code an exception will be thrown which would would break my application.
Reason for that is, that the response request looks like this:
$response = $this->client->send($request);
As a workaround I changed this to:
$response = $this->client->send($request, ['http_errors' => false]);
Obviously I could also make use of GuzzleHttp\Exception to handle these errors aswell. But from what I get, all of this would have to happen inside the package I downloaded via composer which means that as soon as the author releases an update and I run a composer update my changes would be overwritten and my app might be broken until I fix it again.
I guess not everyone is familiar with the Twitch API. An easy example for my question is an API call where you can check wether a specific user is following a a specific channel. When the user does NOT, the response looks like that:
{
"error": "Not Found",
"message": "12345 is not following 67890",
"status": 404 }
So this is a perfectly fine and valid response that would be easy to handle but instead of an 200 http status response the api responds with a 404 http status code which will throw an exception.
So my question is, is it really good practice in APIs to return a 40x status code even though you send and receive perfectly fine requests? It's not like there's an error like missing parameters, ids or whatever. It's just some kind of "bool" query where return can be true or false and where false will always return a 40x http status code but still contains a valid response.
Thank you
Package that is throwing an exception is the best kind, because you can simply write "global" handler for those exceptions and simply "display" error that is sent along, nevertheless you should not.
You should write an API adaptor for Twitch API package and handle errors / exceptions inside those methods instead of using Twitch package right in controller or model. Further more you should delegate making request to dedicated server (such as Twitch) for queued job.
To answer your question:
Are HTTP status codes in APIs good practice?
Yes, where else would you want to use status codes? API is the perfect place.
Status codes are easy to compare, easy to understand. Messages sent along are just meta information for human to "understand" what is going on.
Part below is way off the scope of the question:
You should never change package code itself (except when testing), instead clone/fork package, make changes you need and use composer to load your version instead.
composer.json
"repositories": [
{
"type": "vcs",
"url": "https://github.com/username/repository"
}
],
"require": {
.
.
.
"original-repo-package": "dev-branch-form-your-repo as 1.0.0"
}
I am trying to connect to an API using PHP and its built-in SoapClient. I have checked against the url I was given through the ill-formatted documents the client gave and $client->__getFunctions() returns a list of three functions. HelloWorld($name), which responds with Hello ~name~, shows me that I am communicating with the server through the SoapClient call and the URL is correct.
However, when I try to access one of the other methods that __getFunctions() gives me, even after copy/pasting the XML from the docs and putting in my own credentials, I am still being given an Internal Server Error faultstring and 500 as faultcode from the SoapFault object.
I am sure that it is my own XML string that is causing the issue but I cannot for the life of me figure out how. Reaching out to the API provider directly hasn't proven helpful. This is my first time dealing with Soap/Web Services so I am unsure of where to go from here.
I did wget http//xxx.xxx.xxx?wsdl and it returned me what looks like a valid XML response, the same one I get when I go directly to the url in the browser. What should I be looking into in order to solve this issue? All of the past API's I've dealt with have been JSON/RESTful so I feel out of my element trying to debug PHP errors.
Edit
I have slowly deleted parts of my method call and parts of my XML string, trying to trigger a different error or something in order to find what I need to fix. What I have found is that by not passing in my XML string, I get a valid response from the $client->FunctionCall(...). It's an "this isn't right" message but it's a message! In fact, passing that function ANYTHING for the xml parameter causes the 500 http faultcode/faultstring. Does this mean that my XMl is poorly formatted or does it mean that there is an issue on their end handling requests?
Second Edit
If I make my $client decleration as follows, I get the faultstring Could not connect to host
$opts = array(
'ssl' => array('ciphers'=>'RC4-SHA')
);
$client = new SoapClient($CREDS['orderingWSDL'], array (
"encoding"=>"ISO-8859-1",
'stream_context' => stream_context_create($opts),
'exceptions'=>true,
));
I am getting more confused the longer I try to fix this.
Sometimes a 500 status coming from a SOAP service could be a SoapFault exception being thrown. To help your troubleshooting, you'll want to be able to inspect both your request XML, and the response XML.
Put your code in try/catch blocks, and use $client->__getLastRequest() and $client->__getLastResponse() to inspect the actual XML.
Example:
$client = new SoapClient('http//xxx.xxx.xxx?wsdl', array('soap_version'=>SOAP_1_1,'trace' => 1,'exceptions' => true));
try {
$response = $client->someFunction();
var_dump($response);
} catch (Exception $e) {
var_dump($e->getMessage());
var_dump($client->__getLastRequest());
var_dump($client->__getLastResponse());
}
I'm trying to create a REST service in zend framework. I'm using zend server.
Here's my code:
class ArticleController extends Zend_Rest_Controller
{
public function postAction()
{
//Create the acticle and return it
$data = array("foo" => 0, "boo" => 11);
$this->getResponse()->setHttpResponseCode(201);
$this->_helper->json($data);
}
The HTTP response returns the appropriate headers and JSON data but under the JSON data there's an apache error document.
The only way I can think of to remove the appended error document is to add the following in my httpd.conf file:
ErrorDocument 201 " "
But what's the "corrent" way of doing this?
Your original way is correct. 201 is an appropriate response after POSTing a new resource.
I think that the Error document which you see generated after your own content should not be there. Are you running Zend Server Community Edition v5.0 by any chance? If yes, then see this thread, I think that you encountered the same problem as the other guy there:
How to turn off default HTTP status code errors in Zend Server?
Why are you using code 201? 201 means you have created a resource for the request and are providing a link to it. If you have the article and are returning it you should just use 200.
Otherwise, what you're doing seems like the correct way, you remove the ErrorDocument associated with status-code 201.