Skip to content

JSON Hyper Schema and HTTP Methods

Henry Andrews edited this page Jan 11, 2017 · 6 revisions

This page addresses the recent history and current state of identifying HTTP method usage in JSON Hyper-Schema. This topic has produced a lot of confusion and concern recently, which has derailed several discussions on how to move forward. In order to keep debates on Draft 06 and beyond focused, please read this history.

NOTE: This is @handrews's viewpoint and does not necessarily represent a consensus among project members.

For discussions on adding/restoring the ability to explicitly specify all HTTP methods in JSON Hyper-Schema, please see issue #73.

For discussions on describing non-standard usage of HTTP methods, please see issue #226.

Please do not derail other issues or PRs with these topics!

JSON Hyper-Schema and HTML forms

Originally, hyper-schema link description objects (LDOs) were explicitly intended as analogous to HTML forms. This had the advantage of following the most widely-used approach to links that take user input. However, HTML forms were designed when GET and POST were the only usable HTTP methods. There has never been a need to add support for other methods, as they are usually handled by JavaScript when they are needed at all.

This approach has kept user input (via plain forms) separate from more general HTTP interactions (via JavaScript alone, or HTML forms plus JavaScript). This makes sense for interactive web pages, but API usage is more like JavaScript code than HTML. We need to clearly support all of HTTP, without specifically tying ourselves to that protocol.

First let's go over the HTML behavior, because as of Draft 05 it is still the basis for JSON Hyper-Schema's approach.

HTML and "method"

The "method" keyword in JSON Hyper-Schema was originally identical to its HTML counterpart, and explicitly only allowed "GET" or "POST". However, the HTML5 form submission algorithm only defines a few scheme and method combinations:

  • http: and https: GET forms encode data into the URL query string.
  • http: and https: POST forms submit the data as a payload.
  • mailto: GET forms send email using headers.
  • mailto: POST forms send email using a message body.
  • data: GET forms and all ftp: forms (both GET and POST) discard the data.
  • data: POST forms encode the data into the URI wherever certain character sequences appear.

This obviously limits how JSON Hyper-Schema links can be used. The problem is that URI schemes do not generally define how to map the corresponding protocols to the values "GET" and "POST". That mapping is defined by HTML. So if a given URI scheme is not of insterest to the HTML standard, or is too new for HTML to have taken it into account, there is no clear way to make use of that URI scheme.

HTML and templated URIs

JSON Hyper-Schema has also always supported templated URIs with the "href" keyword, although the exact templating syntax and processing rules have varied. This JSON Hyper-Schema feature is analogous to dynamically generating the form "action" URI on the server before sending the HTML to the browser.

Taking this approach separates user input from programmatic URI computation. In a human-oriented system such as HTML forms, this makes sense. But in a programmatic API environment, the distinction between user-supplied data and data from other sources is not always clear.

Maintaining such a separation is not necessarily desirable with an API. Some applications may gather input directly from users, while others may get their information from a database or configuration file. The API resource should not care.

JSON Hyper-Schema history

"method" in Drafts 00-03

The first four drafts of JSON Schema featured identical wording for the "method" keyword:

This indicates which method should be used to access the target
resource.  In an HTTP environment, this would be "GET" or "POST"
(other HTTP methods such as "PUT" and "DELETE" have semantics that
are clearly implied by accessed resources, and do not need to be
defined here).  This defaults to "GET".

This wording makes it clear that PUT and DELETE (and presumably PATCH) would never appear as values for "method" because of their well-defined semantics.

What's not clear is how to express that PUT, DELETE, or PATCH are supported. Nor is it clear how to indicate the PATCH request media type. Finally, URL query string parameters cannot be used with POST.

"method" in Draft 04

Draft 04 changed this so that the value of "method" is the actual protocol method, while also noting the role that link relations (as specified in "rel") play in determining available and appropriate methods:

This property defines which method can be used to access the target
resource.  In an HTTP environment, this might be "GET" or "POST" (or
other HTTP methods).

Some link relation values imply a set of appropriate HTTP methods to
be used for the link.  For example, a client might assume that a link
with a relation of "edit" can be used in conjuction with the "PUT"
HTTP method.  If the client does not know which methods might be
appropriate, then this SHOULD default to "GET".

With this definitions, if "method" is not specified, the link relation is the primary indication of which HTTP methods are available. Since the default assumtion SHOULD be "GET", then by default if there is a "schema", it applies to URL query string paramters.

However, the behavior of "schema" was still only defined in terms of "GET" or "POST". In particular, there is no indication of whether or how"schema" applies to a "method" of "PUT" or "PATCH". Many schema authors assume that it applies to the request body, but that is neither clearly specified nor clearly forbidden.

If "schema" applies to the request body for "PUT" and "PATCH", then we lost the ability from Draft 03 and earlier to use "PUT" or "PATCH" with URL query parameters. And we still cannot use URL query parameters with POST.

"method" in Draft 05

Draft 05 returned to only allowing "get" or "post". These names were now lower-case to suggest that, as in HTML, they may indicate something other than a literal HTTP GET or POST depending on the scheme. Other values are technically allowed, but SHOULD be ignored.

This property specifies that the client can construct a templated
query or non-idempotent request to a resource.

If "method" is "get", the link identifies how a user can compute the
URI of an arbritrary resource.  For example, how compute a link to a
page of search results relating to the instance, for a user-selected
query term.  Despite being named after GET, there is no constraint on
the method or protocol used to interact with the remote resource.

If "method" is "post", the link specifies how a user can construct a
document to submit to the link target for evaluation.

Values for this property SHOULD be lowercase, and SHOULD be compared
case-insensitive.  Use of other values not defined here SHOULD be
ignored.

The language about link relations was dropped, but language was added to clearly indicate that other HTTP methods could be used to interact with the URI constructed from input to a "get" link. The link relation specification already indicates that link relations can imply HTTP method support, so we do not need to repeat that here.

This is similar to the Draft 03 behavior, with similar limitations but more clarity around using other methods. We can once again use URL query string parameters with PUT, PATCH, and DELETE, but we also once again have no way to indicate which methods are supported. And we still cannot use them with POST.

The only real effect of "method" for HTTP links in Draft 05 is to determine how to use "schema" and "encType". This is important to keep in mind for the next set of changes: we are working from a "get"/"post" world in Draft 05, not from Draft 04's explicit method approach.

Proposals for Draft 06 and beyond

Over the course of the next few drafts, we want to produce a clear and comprehensive solution to all of these problems. This is likely to include:

  • Separate description of URI variable input vs request body (PR #228)
    • If this is done, "method" becomes superfluous, and may be removed (but see below about how to support method hints)
    • If there is a request body schema, it is used for HTTP POST
    • Otherwise, as with Draft 05's definition of "get" methods, any HTTP method may be used, although some may produce a 405 Not Supported.
  • A way to hint at HTTP method support (Issue #73)
    • This could be a redefined "method" keyword, or something else such as "allow"
    • This could be a list of method names to avoid needing to repeat links
    • Like "targetSchema" and "mediaType", it would be advisory only; the resource itself is the only authoritative source
  • A way to hint at the PATCH request media type (not yet filed)
    • Equivalent to the Accept-Patch header
    • Also advisory, the resource can set Accept-Patch differently at runtime (although this would arguably be bad design)

Addressing all of this (and whatever else comes up) will take place over the course of multiple drafts. Draft 06 should make progress, but will not "fix" everything (we don't even have an agreement on what "fixed" looks like). The key point here is that it is not the responsiblity of any one PR to address every problem.

We need to keep this history in mind, and make sure that each PR moves us forward in a way that will help us collect feedback from the community on the next draft. But there will be more opportunities to change and add features.