Clarification on errors during GET requests (404 and partial response)


#1

I’m looking for an example for a 404 response when an object is not found, and in the case of a partial response.

Standard 404 response

If one does:

GET /articles/123 HTTP/1.1

But 123 does not exist, I’m expecting the error response should look like this (according to the specification here http://jsonapi.org/format/#error-objects):

{
    "errors": [
        {
            "id": "1",
            "status": 404,
            "code": "not-found",
            "title": "Article Not Found",
            "detail": "Article 123 is not available on this server"
        }
    ]
}

My question is - is that acceptable?

source and pointer
My second question is where does “source” and corresponding “pointer” go in a response like this?

Partial Responses

My final question is on partial responses…

Example:

GET /articles?filter[id]=1,2,3,4,555,777,999 HTTP/1.1
  1. HTTP status code? If several resources are found but one or more are not found, what HTTP status code should be used? 206 seems appropriate by name, but the actual specification seems to indicate that 206 is only appropriate for HTTP Range requests, unless I’m mis-reading or mis-understanding things (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html).

  2. format: Should error objects just be added to the top-level json for each item that’s not found? I think that’s logical, but I just wanted to double check.

Example:

{
    "data": { ... }
    "errors": {
        [
            {
                "id": 1,
                "status": 404,
                "code": "not-found",
                "source": { ... }
            },
            {
                "id": 2,
                "status": 404,
                "code": "not-found",
                "source": { ... }
            },
    ]
}

I’m presuming, but maybe I’m wrong, but the pointer to the element that wasn’t found would be in “source”? correct?


#2

For the pointer (rather the source in the error) I would use the parameter at least in the second case where one of the requested resources wasn’t found based on the filter query param. I’m not exactly sure how I would represent it though. Perhaps just "parameter":"filter[id]" (I’m wondering if I would try and specify the extract value of the parameter that cause the issue say parameter:"filter[id]=999" assuming 999 was the resource that wasn’t found)

On partial responses; I’m dealing with same issue. The spec says:

The members data and errors MUST NOT coexist in the same document.

I can understand the reasoning for this but there are (as you’ve pointed out) cases where a response can have partial data and we would want to tell the client “here’s what I’ve got and by the way some of it isn’t available and here’s the cause…”. Even if you’re not asking for a specific subset of resources (i.e. filter by id) but when the full set of data may not be available. For us, some back end may be down which would cause a partial listing of some customer data we aggregate under a single resource.

I think it’s a miss that data and errors can’t be in the same document.


#3

Yes, the example 404 response you showed for GET /articles/123 looks perfect.

Source and pointer are optional in the spec because they don’t make sense for every type of error. A GET that returns a 404 is a great example… there’s no request document (which is always what pointer refers to) sent with a GET request, so you should just leave pointer out. There are also no query parameters in your request URI, so you should just leave out “source” altogether.

Note: I’m gonna be a bit sloppy with terminology in my answer below, because my answer would be unnecessarily awkward otherwise.

I think the ambiguity here comes largely from HTTP. That is, HTTP assumes requests are either successes (i.e. 2xx) or failures (i.e. 4xx), but not “partial successes”. JSON API’s "data" and "errors" division is just an extension of this HTTP assumption.

(You’re correct that 206 has a very limited, Range-specific meaning and wouldn’t be appropriate. 207 might be, but that’s from WebDAV, so I’m ignoring it here.)

The right answer depends on the meaning of the URI /articles?filter[id]=1,2,3,4. That URI could mean “exactly the set of articles: {1,2,3,4}” or it could mean “all of the articles, keeping only those whose ids are in the set {1,2,3,4}”. If the URI has the first meaning, then the request has an error if any articles are missing, and so the appropriate status code would be some 4xx. But, if the URI has the second meaning, then the appropriate status code would be 200. And since JSON API doesn’t define the precise meaning of the filter parameter, you have the option to use either interpretation.

Now, if we hold aside JSON API’s requirements for a moment, HTTP let’s you put whatever you want in the response body, so you can easily include both the partial data and the missing ids, regardless of which status code interpretation you use. And you can do something similar in JSON API, but you have to use "meta".

So, in JSON API terms, the two interpretations look like:

  {
    "data": [/* partial results here */],
    "meta": { "not-found": [/* list of missing ids */] }
  }
  {
    "errors": [/* an error for each missing id, perhaps */],
    "meta": { "partial-data": [/* the matching resource objects */] }
  }

Now, this is a bit inelegant, and perhaps its a missed opportunity as @adam suggested. But you can hopefully see at least how it follows from HTTP.

I do think we can improve on this situation in the future by defining an extension to JSON API for this case. I’ve made a note to that effect in the JSON API github issue that tracks possible extensions.


#4

The “meta” solution seems inelegant, yes, but it will work and is what I was looking for. Thanks for the reply.