Imprecise definitions in JSON API 1.0


#1

I’m currently working on implementing the spec and this contains also a validator for the JSON API format. Now I have the problem, that some definitions are a bit imprecise, which makes it hard to implement it properly. Some examples…

Definition of “coexist”, “contain” and "present"
From the spec:

  • “The members data and errors MUST NOT coexist in the same document.”
  • “If a document does not contain a top-level data key, the included member
    MUST NOT be present either.”
  • ‘data’ can be NULL and also an empty array

So IMHO following the spec…

  • it’s valid to use ‘data’ with a value of NULL and ‘include’ (which doesn’t make sense).
  • although ‘data’ is NULL, setting ‘errors’ is invalid (which could be valid).

Is that right or is it a wording problem here?

Allowed link values
The spec includes several examples for ‘self’ and ‘related’ links, and for all ‘self’ values a string is used in these examples - but following the spec, also a link object is allowed for ‘self’ (“a link MUST be represented as either […] string […] link object”).

Is that right?


#2

Hey Christoph! First of all, I saw your other post about extensions and am working on a response. That one just requires a bit more thought and I haven’t had the time yet. To your questions here:

I agree that this is allowed by the spec, but I think it’s ok.

The only time that null is valid as primary data is on a to-one relationship endpoint (like /articles/1/relationships/author) when the relationship has no data. And, if include is used in that case, like GET /articles/1/relationships/author?include=author, it’s arguably more consistent for "included" to be an empty array in the response rather than for it to not be present at all. Otherwise, "included" could disappear sometimes when the same URI is requested based on whether the relationship is empty.

Moreover, adding a restriction that requires "included" to disappear in the "data": null case would be a backwards compatibility break, and I doubt there’s an argument strong enough to warrant that.

I’m not sure I see the problem here… "errors" only occurs on invalid input, which is unconnected to the primary data.

Yup! A link object for self is a-ok!


#3

These seem unambiguous to me.

I would say that {"data": null} and {"data": []} are, in fact, data. They’re “no data”, which is data.

If you have an error, any data the server would have returned may be inaccurate, including null data. In the event of an error, it’s better to omit any possibly broken data the server did manage to pull together, and instead respond with an error document.

Thus, {"data": null} and {"data": []} would both require {"include": []}, if the include member occurs at all.

The string version is a shorthand for when you don’t need any metadata on the link (which would require a full “link object” to express).

Although there does seem to be an ambiguity here. Right before the part you quoted is “The value of each links member MUST be an object (a “links object”).”, which should probably be “The value of each links member MUST be a ‘link’,” and then the section defines a “link” to be a string URL or a “links object”.


#4

What that quoted sentence means is that the value at the "links" key MUST be an object, which is true. Not, “the value of each member within "links" MUST be an object”.


#5

Oops. I missed the pluralization and thought “links object” was the same as “link object”.


#6

Hello Ethan!

I hope you understand my intention. I just want to validate if a document follows the spec, and some definitions are a bit unclear. Perhaps some things don’t make sense, but as long the spec allows it, it’s valid.

I’m not sure I see the problem here… “errors” only occurs on invalid input, which is unconnected to the primary data.

So you mean errors are allowed in response documents only? This makes sense, but also isn’t defined that clearly in the spec. It says that it’s used to inform about errors “while performing an operation”, which could also include operations on client side and therefore used in request documents.

But the main question was: "Can I use errors together with data set to NULL or not?
Which can be translated to: “Are keys with a value of NULL handled like keys that do not exists in the document?”

You said that this is not the same, and that’s what I wanted to know - at least for data (in other cases it’s treated the same, e.g. the pagination links: “Keys MUST either be omitted or have a null value to indicate that a particular link is unavailable.”).


#7

Yes, absolutely! And I appreciate you taking the time to go through the spec so carefully and identify these cases, and then to make a validator, which could be very helpful for the community. I’m sorry if anything in my reply came off as confrontational!

You’re right, and I’d be open to a PR that makes this explicit.

Hmmm… I agree with you that that sentence definitely seems to imply that an omitted pagination link is the same as a null one. But I wonder if that’s intentional or if it’s a bug (and, if it’s a bug, what we can do about it, if anything).

If it’s intentional, it seems very inconsistent to me since, even for other links, an omitted link probably wouldn’t be the same as a null one. For example, an omitted "self" link would presumably just mean that a "self" link wasn’t provided, whereas a null "self" link, if such a thing were allowed, would mean that “there exists no URI at which this individual resource object can be accessed”.

All of this, I think, is very closely related to the contradiction identified in #887, which shows that these cases may have been overlooked a bit, and we have to figure out what to do about them.


#8

to make a validator, which could be very helpful for the community

Yes, I hope so!

I’m sorry if anything in my reply came off as confrontational!

No, everything okay. :smile: Just wanted to note that, because all my questions about the spec and constructed examples/edge cases.

You’re right, and I’d be open to a PR that makes this explicit.

So it’s okay for you to change it in JSON API 1.0, because this is, what has been intended? This is a topic in my document (in which I suggest to introduce a PATCH version, exactly for this purpose - to clarify points in a spec without changing the intended behavior, but allow to track these changes).

All of this, I think, is very closely related to the contradiction identified in #887, which shows that these cases may have been overlooked a bit, and we have to figure out what to do about them.

Oh good, that’s a point I also wondered about.


#9

I’d support text like this:

Clients SHOULD NOT send "errors" in request documents. If a server receives such data, it SHOULD ignore it. JSON API defines no meaning for "errors" in request documents and, because of the nature of the HTTP protocol, a server receiving such data would have no simple way to determine which of its prior responses triggered the error condition in the client, even if it wanted to fix the problem.

I favor a SHOULD over a MUST because:

  1. it’s possible that we might define a meaning for "errors" in request documents in the future—especially if JSON API is extended to two-way protocols like websockets; and

  2. a MUST would technically be a backwards-compatibility break, whereas a SHOULD would not. And since we might want the flexibility of a SHOULD anyway, a MUST just doesn’t seem to make sense.

But I do favor a SHOULD over no change at all, because I think the SHOULD text would clarify things a bit.