[RFC] Standardising an OPTIONS response on a server that supports jsonapi

The jsonapi spec is a very clean and elegant way to make requests and decode responses for an application that provides and API. And as far as I can see is one of the best implementations of the HATEOAS principle.

The only thing lacking, in my opinion, is that although you can now in theory traverse an entire api based on the links provided in a response, there is no way of knowing how you can manipulate those resources, other than brute forcing to a resource url, trying different combinations of HTTP verbs and attributes.

The HTTP/1.1 specification section 9.2 page 51, describe the OPTIONS method, and in part states that when a request using the OPTIONS method on a specific resource is made:

The response body, if any, SHOULD also include information about the communication options

I propose that we make a standard jsonapi response to an OPTIONS method request.

As a first pass something along the lines of adding a new top level key, called options with the following structure:

{

 "options": [ 
    {
      "type" : "articles",
      "method": "POST",
      "attributes": {
        "body": "string",
        "author": "string"
      }
    },
    {
        "type": "articles",
        "method" : "PUT",
        "attributes": {
          "body": "string"
        }
    }
  ]

}

The above is just an example, that serve to illustrate that when creating an article you have to provide both a author and a body, but when updating an article you cannot change the author.

JSON Shema might be the best tool for describing the format of the content inside the attributes key, as it can give type, occurrences along with human readable descriptions.

Please provide your thoughts and concerns?

Well, shouldn’t the header be specified as well?

E.g. it must have an Allow: GET, OPTIONS, HEAD, PATCH, DELETE (depending on which are available.)

Also I think an options endpoint should be mandatory, at least in the stripped down version that tells you which methods are available.

@lukasoppermann Agreed, I also think that all api’s should respond to OPTIONS at the very least to be HTTP/1.1 compliant.

But the Allow header is already very well defined in the HTTP/1.1 spec.

What isn’t well defined is a way for us to communicate the data that should be sent along with each of those methods.

IMO what we need is the equivalent of html forms, but for the jsonapi spec.

If we had such a specification the entire API would be self documenting and discoverable, and if a “system” is well designed you could probably get the response to an OPTIONS request for free, and this is a very exciting concept!

IMO what we need is the equivalent of html forms, but for the jsonapi spec.

Oh please no. One of the reasons I chose JSON API was because it didn’t support this.
If you want this kind of capability there are other hypermedia formats that provide this (e.g. JSON-LD+Hydra, Siren, UBER).

a way for us to communicate the data that should be sent along with each of those methods.

I’d rather do that through separate API documentation (e.g. Swagger, RAML)

@jlangley It doesn’t seem like this idea has any support. Why do you prefer separate documentation? In my experience, external documentation always goes out of sync with what is actually happening in the API

Because I think that API client developers need to know about this sort of thing at design / develop time. I think it is too late by run time to build a really good UI. (Sure you could build a generic client driven purely from the API responses, but I don’t see how you can manage the layout / styling of the UI well if you don’t have some advance knowledge of what data you might need to send / receive.)

There are two ways around this.
The first is to generate the API docs from annotations in the code. This is the method I prefer for internal APIs (i.e. an API developed by a team for their own use, and not published / made available to other teams).

The second, which I prefer for public APIs, is to take an API-first approach. The API documentation becomes the spec, and automated tests are generated from this documentation / take it as input, and generate errors when the implementation doesn’t conform to the spec. With API Blueprint you can use a tool like Dredd for this. With Swagger the tooling is not so good, but you can run automated diffs on docs created from the source versus the docs created by the API designer to detect differences between the spec and the implementation.

@jlangley but then it is impossible to create a RESTful API with jsonapi?

From REST APIs must be hypertext-driven

A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API).

Honestly I don’t know whether what I’m doing counts as “RESTful according to Roy”. (I don’t understand his arguments well enough to work out whether I’m complying or not.) But:

  1. I don’t care. I’m using JSON API combined with a profile, even if it is not “proper REST” (it might be), it is REST-like enough for me.

  2. I don’t actually see anywhere that JSON API claims to be REST compliant.

@jlangley I don’t either. But if we want api specification documented outside the API itself, we don’t need links, as they become redundant.

There’s no harm in having both though. External documentation is especially useful when you want to have more variation on the links than are easily provided in the payload - for example, pagination links would typically give first, last, next and previous. No easy way to jump to a given page, or to change the page size, or anything like that unless you want to have dozens or links returned for a single resultset.

@Sazzer I can’t imagine a situation where you would have so many links from a resource that it would become unmanageable.

For your specific example, when you want to specify something like pagination links to specific pages you should use URL templates

@A-Helberg Ok - I’d not come across that before. Are they valid in JSON API Links?

Take, for example, faceted searching. Your search results might want to specify a number of facets and values that you can filter on to restrict down what you are seeing. If you are providing a link for every single value of every single facet then this can get to be very big very quickly. If you instead simply provide the facets and values then the payload size is much smaller, and if the client knows how to then it can build the URLs from those input values. If using these URL Templates in JSONAPI is valid then this becomes possible to do.

JSON API wants you to use a filter parameter for this.

Yes it does. But something has to provide a list of possibilities for these parameters. That will either be external documentation combined with some data from the payload, or a large number of links in the payload. (Or just external documentation when the possibilities aren’t dependant on the previous payload)

I disagree.
The links say what you can do right now, i.e. based on the current state of resources held by the server. The client cannot know that in advance.
However, the client can be told in advance that when a certain action is available, the client must supply certain information (i.e. the POST / PATCH body) in order for the server to carry out the action.

Well, a client could assume that it is entitled to filter on any of the resource’s attributes (and then the server could return error responses for requests it does not support).

But I agree that is pretty unfriendly to the client developer, so personally I would put a list of filterable attributes in the API documentation. As you suggest, providing links for every option and every combination of options could significantly bloat the server response, and probably would be hard for a client to parse and present sensibly back to the user.

I can easily imagine different clients offering different subsets of filters appropriate to their particular users. That feels like a client design time consideration, rather than a runtime consideration, so fits with my current rule of thumb about how different aspects of the API get communicated.

I have to confess, the more I think about it the more I’m starting to wonder against the idea of hyperlinks in the payloads that tell you what to do next. It works fantastically for simple cases, and it seems like a brilliant idea, but it starts to feel like it’s just making life harder for some situations where you end up breaking out of the resource payload anyway.

And I know the big argument in favour of hyperlinks is that the server can do large-scale reorganisations and the client doesn’t need to know or care, because the new links provided will just work. But unfortunately it just doesn’t work that way in real life.

I disagree (as outlined above in reply to @A-Helberg).
Just because we can’t use them for everything, that doesn’t mean we shouldn’t use them for anything.

That’s true. I’m just a huge fan of consistency is all. It gets awkward using an API when some things work one way and other things work in a completely different way. If everything is the same then you know what you’re dealing with.

@Sazzer as @jlangley said you would use a filter parameter for “faceted searching”. And I agree that having a link to each possible value for search value is not the way to go, and hence the reason for starting this thread, which I’ll explain in a bit.

You are right a client can know in advance when a certain action will be available, and the way you do that, is by making your client privy to business rules and logic. This is a very bad type of coupling and exactly the reason HATEOAS was introduced.

Correct but what about the case where the filter parater is not an attribute on the resource?

And any of a multitude of API updates would, invalidate your client.
Consider the case, mentioned above, where a client only cares about a certain filterable attribute, the only breaking change I can think of right now, is a name change. If the client was able to get the filterable parameters from the API. The absence of the parameter it cares about, means it’s no longer available and the client and degrade gracefully.