Zabbix API behavior with no "id" specified -- no JSON in response - json-rpc

I am writing JSON-RPC code to talk to the Zabbix API.
I have noticed that if I omit the "id" from the request, I get back a response with zero-length content. If I specify any "id" value, the content is a JSON object as documented in the API documentation.
Can I assume that if I provide "id" that I will always get back JSON describing the error if an error occurs, but otherwise I will get back a zero-length content and a status of 200 to document the success? I always want to know about errors, but for successful operations (like deleting something) it often will suffice to know that it succeeded.
Is this a general rule? Is it documented anywhere? If so, please tell me where.

According to the JSON-RPC 2.0 documentation, "A Notification is a Request object without an "id" member." The documentation goes on to state: "Notifications are not confirmable by definition, since they do not have a Response object to be returned. As such, the Client would not be aware of any errors (like e.g. "Invalid params","Internal error")."
So, if you omit the "id" it will never return an error, because it is a notification. For use with Zabbix, you should probably just stick to using an id. That way you can get verification and error messages.

Related

API design - Optional body in client request - Status code to return if validation fails

In our API, one of the endpoint will expect clients to provide body/payload only in certain scenario.
If the API is unable to generate a payload for given request based on the origin of the client then, we want our API to provide response with the right status code to the client, so that they know they have to provide additional information. Once the client fulfills the request with body/payload then the api will process the request as normal.
I just wanted to know is there any standard, predefined status code or procedure to implement this kind of endpoint in API design or do we have to just reject the request with some custom status code and then ask the client to implement a logic based on custom code?.
Thanks,
Vinoth
HTTP Status codes don't, nor are they intended to, map precisely against every real world error. They represent categories of error.
For example, a 404 means that the resource couldn't be found, but if your path is /customers/11/animals/5 then there are several things which could be wrong with the path. customer 11 may not have an animal 5 for example, or there may be no customer 11. There is no http response for "animal not found". Or your API may not have any calls with that pattern of URL to begin with.
You should return a status code which represents what "category" of error you have (in this case, something was not found), and the response body should contain more specific details about the error. To make things simpler, I find it helpful if the data structure is the same for a success and error (it makes parsing much easier) with a "data" field which varies per response.
Here is one example:
status code: 404 not found
body: {
"messageDetailCode" :"CustomerNotFound",
"messageDetail" : "Customer not found",
"data" : null
}
Further reading:
What's an appropriate HTTP status code to return by a REST API service for a validation failure?

What is the best HTTP status code error for failed password update?

I'm building some REST API to be used in a native iOS/Android app.
One of the endpoints allows the user to update his password by providing 2 fields: old_password and password.
Which HTTP status code should I in the situation where the old_password is incorrect?
My first thought was a 401 error but I already use it when the authentication token is invalid and it automatically triggers a logout in the app.
400 doesn't seem to fit because the request is actually semantically correct, it is a specific authentication error. Maybe 422?
One thing to keep in mind is that status codes, like response headers, are metadata; they are there so that generic components that know nothing about the details of your API can participate intelligently -- for example, by invalidating caches, or throwing up dialogs to collect authentication credentials.
400 doesn't seem to fit because the request is actually semantically correct
In practice, 400 is usually fine; clients are supposed to treat an unrecognized 4xx class status code as they would treat 400. Put another way, you can use 400 unless you specifically want to induce a different behavior by the generic components.
For your specific case, 409 Conflict is probably the closest match
The 409 (Conflict) status code indicates that the request could not be completed due to a conflict with the current state of the target resource. This code is used in situations where the user might be able to resolve the conflict and resubmit the request. The server SHOULD generate a payload that includes enough information for a user to recognize the source of the conflict.
RFC 5789 suggests a distinction between 409 and 422 that may be interesting. Paraphrasing this distinction
422: This might include attempts to modify a resource in a way that would cause the resource to become invalid
409: the request cannot be applied given the state of the resource.
You can also make a reasonable argument that the entire 4xx class of response codes is inappropriate. For example, if the request method is POST, then the server is expected to
process the representation enclosed in the request according to the resource's own specific semantics
Which it did; successfully, even. It just didn't produce the most commonly expected successful result.
On the other hand, the JSON Patch would argue the other direction; your attempt to change the password would probably look something like
[
{ "op": "test", "path": "/password", "value": "old_password" },
{ "op": "replace", "path": "/password", "value": "new_password" }
]
If you provided the wrong password in the test, then that operation would be considered unsuccessful, which would in turn mean that the PATCH is unsuccessful. That in turn would invoke the arguments for error handling as described in HTTP Patch.

HTTP Status codes confusion

So, I am trying to display meaningful and accurate HTTP status codes and I'm getting confused even after going through the examples online. Here's my situation:
In the URL which accepts the query param:
#POST query
Sample URL: /putRecord?Name=A&Age=25&house=permanent
what status code do i return when one of the params is missing? (All 3 are mandatory) - from what I've read, I am guessing it is a 400: Bad request. But this seems too general. Is there a way for me to say that the query was malformed? Source:here
Assuming I validate the name for duplicates against the DB, if I get a duplicate, what status code do I return?
So, if there's a duplicate entry available already, I can't add the record. Do I display 304 (Not modified) or just the error code from 2?
Clarification: For 3, another possibility is when I can't actually commit to the DB and I rollback(possibly). What status code will it be now?
Thanks so much!
Ad 1. You can return, besides the code itself (400) also a short message with explanation. So, instead of returing "400 Bad Request" you could respond with "400 Query param name required" or something similar. This message is called "reason phrase" and is defined in 6.1 in RFC 2616. Or, if you need more flexibility, you could return document with the explanation.
Ad 2. I would consider using 422 Unprocessable entity. From the RFC 4918:
The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity, and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions.
Ad 3. I would return 422, but it really depends whether this situation is considered an error in your logic, or is it a regular, expected situation.
Edit: As #War10ck suggested in the comment, HTTP 409 (in place of HTTP 422) might make sense as well.
Note on handling duplicates: it seems (correct me if I'm wrong) that you consider new entity being a duplicate if it's name is already in the database. If so, that you could maybe consider using a HTTP PUT instead of HTTP POST?
You could define the following resource:
HTTP PUT /record/:name
So, "name" would be a part of the URI. Then, in case there is a second PUT to the same resource (same "name"), it'd be elegant to respond with 409/422.
If you're using different key for unique constraint, modify the URI appropriately.
As a rule of thumb, POST is for situations where you can have multiple instances of a given resource, i.e.
HTTP POST /log ;; Because we have many logs
And PUT for situations where each resource is unique:
HTTP PUT /person/:name (or /person/:tax-number if :name isn't unique)
Also, note that I've renamed your resource from "putRecord" to "record" - PUT is a HTTP method, no reason to have it in URI as well.

How should an error be returned to a REST client (if at all)?

I have a REST resource that returns tabular data:
http://example.org/api/tables/foo
This returns the first page of results from the foo table.
There is a query parameter to add a selection criteria to the resource:
http://example.org/api/tables/foo?id=bar
id=bar is not a free text query. Internally the server attempts to resolve bar to a known entity and creates a regular expression limiting the rows returned from foo. For this query to succeed bar must be an ID that the system is aware of - otherwise the regular expression cannot be generated appropriately.
What's the correct behavior for this resource if bar is not known to the system? I understand that 5xx responses are not appropriate since the client cannot call again and expect a different result. Is it appropriate to return a 404 response with a message detailing that bar was not recognized? Or is it better to return a 200 response (since this is a search result) with some envelope wrapping the empty search result detailing that bar could not be found? Something else entirely?
It all depends on your business domain.
If a call to an unknown entity is a failure in your domain - you should provide an error status code of 4xx (if I understand you correctly, the resource was not found - so a status code of 404 Not Found will be appropriate in here).
If a call to an unknown entity is ok, it just yield no results (lets say a google search that yields 0 results) you should provide a status code of 2xx.
Status codes 5xx are server error, and they tell the client that there is something wrong with the server side. In your situation there is nothing wrong with your server, so a status code of 4xx will be appropriate in here.
By the way, you don't have to use all the error codes for every error - basically if you go over you business domain, you will see that you can use only a small subset of these codes to describe your errors.
Be sure to provide a detailed message back in the response so that the person using your service will get as much details and information as possible.
If you can, provide links to online resources explaining the problem. For example, if you have a developers forum thread discussing this exact problem - provide a link to that thread.
If you have to use error codes, use string codes rather then random numbers, for example: use "UNKNOWN_ENTITY" instead of error number #9842.
Example for an error message:
{
"message" : "Unknown entity provided".
"description" : "Parameter bar is not known to the system.",
"errorCode" : "UNKNOWN_ENTITY",
"links":
[
{ "rel" : "help",
"href" : "http://myforum.com/errors/unkownEntityError",
"title" : "My Forum"
},
]
}
This is a question often up for debate, but most people will use 401 Unauthorized or 400 Bad Request to indicate errors. I typically use 401 for login failures / authentication failures and 400 for bad parameters. In the message body of a 400 response, I often return a message indicating the bad parameters.

REST design - An operation with multiple possible non-success payloads

I'm trying to design a REST method for an 'Add person' operation that has a bunch of business rules. There are multiple possible non-success payloads (for the business purposes), requiring defined structure (to allow the consumer to parse the detail).
For 'Add a person', one of the following non-successes could happen:
We believe the system already has person.
Payload: The ID of that person
There are some possible matches.
Payload: A list of possible duplicates, and an override code to submit the record 'for sure'
General validation errors
Payload: Array of 'Error' object. (Standard across the API)
Question - Response object
If they're all to return under a single HTTP error status code, would it be right to have a varied object like:
OverrideCode (for (1))
PersonPossibleMatches [] (also for (1))
PersonDuplicateId (for (2))
ErrorList [] (for (3))
And have the consumer + documentation explain the interpretation?
Question - Response code
Is 400 (Bad Request) the correct (or correct enough) HTTP status code for this? We use it largely for the field validation (also scenario (3) - just wondering if business rule / 'intermediate state' things like this are any different.
Are there a more appropriate codes to spread the 3x scenarios over? And is it ok for the payloads to be different?
Thanks.
There are two aspects you need to consider
HTTP response code.
Error response payload.
Point number 1 is relatively simple. You have 400 error code for bad requests. And 409 for conflicting resources. So far simple.
Now let us consider your scenarios:
We believe the system already has person.
Payload: The ID of that person
Design suggestion: you can send a response like below
Response code: 409
{
"error_code": "resource_exists",
"error_description": "Resource person with ID XXX already exists"
"debug_info": "",
"link" : [
{
"href": "http://host-name/persons/123456",
"rel": "person"
}
]
}
2. There are some possible matches.
Payload: A list of possible duplicates, and an override code to submit the record 'for sure'
Design suggestion:
In this case - you may want to use PUT to override the resource. No need to use special code.
Response Code: 400
{
"error_code": "potential_duplicates",
"error_description": "Potentially the resource is duplicate of one of the following. Please use PUT with the resource ID to update"
"debug_info": "",
"link" : [
{
"href": "http://host-name/persons/234",
"rel": "person"
},
{
"href": "http://host-name/persons/456",
"rel": "person"
},
{
"href": "http://host-name/persons/789",
"rel": "person"
}
]
}
General validation errors
Payload: Array of 'Error' object. (Standard across the API)
Design suggestion: Here you can simply use 400 response code and a meaningful response like the examples above.
This depends in part on how the operation is performed. Since you said the operation has a bunch of business rules, and the system returns a payload with an ID when the person already exists, let's assume the operation is non-idempotent due to unrelated side-effects, performed with a POST to a factory endpoint.
1. We believe the system already has person.
This is a no-brainer. As suggested by others, you should use a 409 Conflict status code, with a body describing the nature of the conflict. In this case, it seems like there's nothing else the user needs to do, and he can move forward to the next step in the workflow. If there's something he can do, it should follow a procedure similar to the next case.
2. There are some possible matches.
Assuming that the clients don't have any key to unambiguously identify a person, which seems to be your case since you're considering possible matches, here you should also use a 409 Conflict status code, with a body describing the nature of the conflict, but with instructions on how to solve it.
Some other answer suggests you to allow an overwrite parameter that could be used any time, other suggests using a PUT, but I disagree with that since there's nothing preventing a client from using the overwrite all the time, or skipping the POST and use the PUT to replace an existent close-match. Also, you may have concurrent clients trying to add or change a person that match each other, or a common existent group, which will lead to an ABA conflict.
The conflict resolution body should return a valid tag for each possible match, and the client should be instructed to resubmit the same request with the If-Match header and the collection of tags. It may be a single tag, as long as it's generated from key data from each member in the collection. This will enforce that the user first must try the request without any override. If there's a conflict the user is forced to specify the exact entities that will be overwritten, and you're protected from inconsistent updates in case someone changes the current state between the first and the second request.
If the tags don't match in the second request, meaning the state was changed by something else between them, you should fail with a 412 Precondition Failed error.
3. General validation errors
This is also a no-brainer. A 400 Bad Request detailing the error, which seems to be standard across your API.
You could use 409 for the duplicate entry - and arguably for the possible duplicate entries with the extra info in the payload.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.10
A 400 for validation errors would be the expected response.
It is a judgement call at the end of the day and it depends what would be easier for your rest clients and what they are doing.
Here's the design process I use when creating RESTful API responses for error cases:
Design the response payload for the error condition. Regardless of the error code that's used, it is always good practice to return some content within error responses so that clients can learn more about the error and how to avoid it in the future.
If there is an HTTP status code that accurately describes this error already, and it's not already in use for another error case, use that.
If the closest matching error code is already being used for another error case, it's still OK to use that code, but the response payload becomes the place where the different error cases under that code get distinguished from each other. Your documentation should clearly state that inspecting this code wouldn't be enough, and that clients should then also look into the response to see exactly what happened.
If none of the above are applicable, use the closest error code that's appropriate. Just as in #3, the documentation of your response payloads makes this approach possible. If it's an error that the client influenced, make it a 400-range error, probably 400 - Bad Request. If it's the server's fault, then it should be a 500-range error, probably 500 - Internal Server Error.
Please, please, never throw 200 - OK for errors. The world left that nonsense behind in SOAP land, and nobody wants to go back.
Now let's apply that thinking to your error cases:
We believe the system already has that person. As correctly stated in another answer, 409 - Conflict accurately describes that error, so you should just use that. Putting some descriptive error information in the response payload would help new users of your API, even with such a definitive and understandable code.
There are some possible matches. There really isn't an HTTP code that describes this, and it's something that the client could influence, so the closest would be the catch-all code of 400 - Bad Request. Including the list of possible duplicates is an interesting idea, but make sure you don't end up returning enormous responses with huge numbers of possible matches. Also, make sure to also return URIs to those matching resources so that your clients can easily consume them. As for the "override code" suggestion, I wouldn't return that in the payload. Rather, I'd just document a parameter to your "Add a Person" operation that would allow for overrides to occur at any time, not just after a failed first attempt. For example: POST /people?overwrite=true.
General validation errors This is definitely a job for 400 - Bad Request, along with a descriptive error payload. It sounds like you're already allowing an array of errors to be returned from any API call, so that should be good enough to capture all the validation failures for the client-supplied data.
How about explaining it with a payload back; That is how we deal with REST responses for clients.
Response HTTP 409 with following payload response indicating to client what should they do next
`
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<request-result>
<http-code>200</http-code>
<description>REST Request is successfully processed</description>
<internal-error-info>Person already Exists</internal-error-info>
<message>Person with <id> already exists in sytem. Try picking different ID/Name combination</message>
<requested-operation>Add a Person</requested-operation>
<resource-name>Person</resource-name>
<status>SUCCESSFUL</status>
</request-result>
`