Question

I'm wondering how best to model in a HATEOAS based API links that allow the client to set parameters. E.g. imagine a search response that returns a list of producst and then refinements that can be performed on them:

{
    "results" : {
        ...
    }
    "refinements" : {
        "Size" : {
            "links" : {
               "extra small" : "/products?size=xs",
               "medium" : "/products?size=m"
            }
        }, 
        Price : {
            links: {
                "greater than" : "/products?priceGreaterThan=aValue",
                "less than" : "/products?priceLesshan=aValue",
                "between" : "/products?priceLesshan=aValue&priceGreaterThan=aValue"
            }
        }
    }
}

The size refinements seem straight forwards but the price refinements require the client to pass a value. How is this typically represented in a HATEOAS link?

Was it helpful?

Solution

I highly recommend that, when using hypermedia, you use a hypermedia enabled media type. There are many JSON based media types out there that support form-like interactions.

Here is an example using JSON Hyper-Schema. It behaves just like an HTML Form with method="get".


/product

HTTP/1.1 200 OK
Content-Type: application/json
Link: </schema/product-list>; rel="describedby"

{
  results: [ ... ]
}

/schema/product-list

HTTP/1.1 200 OK
Content-Type: application/schema+json

{
  "$schema": "http://json-schema.org/draft-04/hyper-schema#",
  "links" : [
    {
      "rel": "search",
      "href": "/products",
      "schema": {
        "type": "object",
        "properties": {
          "size": { "enum": ["xs", "m"] },
          "priceGreaterThan": { "type": "number" },
          "priceLessThan": { "type": "number" }
        }
      }
    }
  ]
}

A generic client can build all of the links from your example and more with this schema. Other examples of media types with similar capabilities are Siren, Hydra, and of course HTML.

OTHER TIPS

Your going to hate(oas) this answer but my interpretation of the original idea would be:

<form method="get" action="products">
    <input type="number" name="priceGreaterThan"/>
    <input type="submit"/>
</form>

You have given full interpretable information on what to pass and how to pass it in Hypermedia format.

In fact before i get a million down votes let me back myself up with some Roy Fielding quotes:

A truly RESTful API looks like hypertext.

and

Think of it in terms of the Web. How many Web browsers are aware of the distinction between an online-banking resource and a Wiki resource? None of them. They don’t need to be aware of the resource types. What they need to be aware of is the potential state transitions — the links and forms — and what semantics/actions are implied by traversing those links.

and

the media type tells the client either what method to use (e.g., anchor implies GET) or how to determine the method to use (e.g., form element says to look in method attribute).

Other than the ones mentioned by Jason, Collection+JSONs Query Templates may be a good fit here though I'm not a huge fan of its verbosity.

Perhaps more elegantly, HAL uses URI templates to describe parameterized links:

{
    "_links": {

        "ea:find": {
            "href": "/orders{?id}",
            "templated": true
        }
    }
}
Licensed under: CC-BY-SA with attribution
scroll top