Pattern for responses from HTTP JSON API - php

I have a HTTP JSON API, which runs on php, on a small framework. This API is a wrapper for a databases pgsql functions.
Php framework returns responses in such way:
{
code: 200,
data: []
}
Codes are HTTP code responses (such as 200, 301, 302, etc). pgsql functions returns their own code (negative values for errors, positive for success results), message (meaning of code) and result data:
{
code: -1,
message: 'Wrong data',
data: []
}
So, my packages from API are:
{
code: 200,
data: {
code: 1
message: 'Succeed'
data: []
}
}
Isn't it messy?
Occur some confusions when writing client code, that requests this API.
Maybe there are some standard patterns for making some kind of packages of API.

Your API layout is not messy. As Botond suggested, it is actually pretty logical. The only change I would make to it would be to move your status codes into HTTP headers rather than in the JSON data, to reduce the format a bit. This will also allow you to easily differentiate between successful calls and errors.
Suppose your API can answer with 4 different codes: 200, 201, 403, 404. Respectively: done, not changed, forbidden, not found. Instead of passing this as a JSON variable, you could easily bind it into the HTTP response header, as the values already exist and are well understood. This, as in this question, is a pretty well-accepted method of providing status codes, provided that you are not using this specific header for anything else.

See you have to read the responses in Iterative manner. You can read the JSON response and then check if the data field has another object/array.
You have to assess the code and show error messages on all codes except 200.

Related

Laravel forcing json response for api

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)

HTTP status codes in APIs good practice?

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"
}

php http post response for web hook

I'm trying to create a web hook notification. The documentation of the service i want to use requires that i specify a URL where POST requests can be performed. This URL will receive the following object, in json format, and must respond with a Status Code between 200-299.
{
"type": "ping"
}
I don't know how to proceed making my server on localhost respond with a 200 status code. http_response_code(200) works well on live server but nothing seem to be happening on localhost.
Is there any way i can make it work with localhost?
I've included the link to the documentation here (i hope it's not against the rule).
I am thinking that you wouldn't have to send them the response. The webhook would know about the response. If it reached your URL successfully, it would be a 200 OK right off the bat. If the API is requesting a response back then I imagine that you would have to call it back somehow. Is this a well-known API? Any documentation?
The response code is in the response header, not in the content.
PHP defaults to a response code of 200, so if you don't mess with it at all, you should be good.
If you want to set a different response code (202 for example), just call:
http_response_code(202);
Or set the full header yourself:
header('HTTP/1.1 202 Accepted');
Proper way to explicitly set 200 (or any other) status code with http_response_code function is just as following (don't echo or json_encode it):
http_response_code(200);
It should force webserver to use 200 status code in it's response. However, webserver could possibly ignore it. To check what response code your webserver sends, use telnet or any REST tool like Postman

REST API - HTTP status codes with multiple errors

I'm currently in the process of creating a small API. I have some error conditions, the 3 in question in this case are:
The user making a request with any method other than POST
The user not being authenticated
An entity not being found; resulting in no action being able to be made.
In that order. I had originally decided that I could assign a status code to each of these errors, (i.e. 400, 403, and 404, in that order) but then realised that I can't set multiple HTTP status codes.
How does one deal with this issue? Should I use HTTP status codes?
In my view it should check each of these conditions in the order you specified and return immediately with the corresponding error code if one of the conditions fail.
So only 1 error code will be returned.
It would be OK to use HTTP status codes, but it depends on who is consuming your API. Sometimes it is better to just return 200 OK and then include Error information in the body.
With Status Codes
If you go with status codes just return the first error encountered, no use in handling the request further anyways, so in pseudo:
if (request is not POST) return 405; //abort here
//we know request is POST here
if (request not auhtorized) return 401; //abort here
//we know request is POST and authorized
if (request requests a not exisiting entity) return [404, 422, ..., 5xx] either will do; // abort here
// we now know the request is POST, autorized and requests valid information
processRequest();
Without Status Codes
As an alternative, since you tagged ajax, I assume you are returning JSON, so just return 200 OK and include a the fields success : [true|false] and errorMessage : ["Not POST"|"Bad Auth"|"Bad Request or Unknown resource"|"OK"] in your JSON answer.
You could also combine both ways, but depending on the ajax client not all will work well with all status codes. Given the information in the answer, all you need to do is check if success === true and handle error otherwise.

Json RPC request via jquery getJSON

I am trying to send json-rpc request to remote server with jquery getJSON method. Here is my code:
json_string=JSON.stringify(obj);
var jqxhr = $.getJSON("https://91.199.226.106/ssljson.php?jsoncallback=?", json_string, function(data){
alert("aaaaaa");
});
jqxhr.error(function() { alert("error"); })
Here is my json-rpc string example:
{"jsonrpc":"2.0","method":"merchant_check","params":[{"hostID":150999,"orderID":116,"amount":"150","currency":"051","mid":15001038,"tid":15531038,"mtpass":"12345","trxnDetails":""}],"id":116}
And here is the error I get:
{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"Invalid JSON-RPC 2.0 request error (-32600)"}}
I can`t get what is the issue. Am I doing something wrong? Maybe I need to send request with php and not jquery? Then how should I do it?
The getJSON as the name say will send GET request if you want to use JSON-RPC you need to use POST like:
var json_string = JSON.stringify(obj);
$.post('https://91.199.226.106/ssljson.php', json_string, function(response) {
// process response
}, 'json');
but this will only work if your page is on the same server, unless you use CORS.
That specific error message is supposed to tell you that the message envelope is invalid per the JSON-RPC 2.0 spec, or that there's a parse error in the JSON itself.
Unfortunately, in practice, many services return this error under a much wider variety of circumstances. (e.g.: missing authentication token, etc)
Specific problems with your example message?
Does the web-service accept GET requests? (i.e: should this be a POST instead?)
Does the web-service actually require the ?jsoncallback=? bit? That's normally for a JSONP request rather than JSON-RPC. The service is returning a real JSON-RPC error status, so I'd be really surprised if it needed that GET parameter, and (depending on the web-service configuration) might be interpreted as part of the envelope, which would make it an invalid JSON-RPC request!
Does merchant_check take an array of one-or-more transactions as its only parameter? If not, then you've got the syntax wrong for params. Some services want params to be an Array, some services want it to be an Object. Consult the SMD/documentation to determine which is the case.
The service might require text/json (or something else) as the mime-type for the request.
Recommended Approach:
To avoid these issues, you should probably start by using a purpose-built JSON-RPC library, like the one provided in Dojo toolkit, and use the SMD published by the web-service if it has one. (I recommend against hand-constructing JSON-RPC messages).

Categories