Skip to content
This repository was archived by the owner on Nov 6, 2025. It is now read-only.

Hypermedia API Design

Andreas edited this page Jul 31, 2013 · 2 revisions

Hypermedia API design session

Convener

[Andreas Schmidt]

Based off the design around the Nokia Places API

Attendees

[FirstName LastName (@twitter)], …

Notes

Places API is an API for local discovery and information retrieval. Design goal was to build an API that provides entry points for various local discovery use cases. As local discovery is usually a multi step process, hypermedia links in the API responses correspond to the steps in such a use-case flow.

The API supports JSON representation only, using various json media types for different resource representations.

Hypermedia link representation

All json representations share a common representation for hypermedia links:

The minimal link object has two attributes:

  • href : the URL to the linked resource
  • type : the media type of the linked resource; either a RFC 2046 media type for links to external (web) resources, or for hyperlinks within the API a URN identifying the json media type of the linked resource (e.g. urn:nlp-types:place)

Additional link attributes:

  • title : for hypermedia links intended to represent a step in the use case flow, this represents a title for that navigation element in a UI. The title is localized according to the apps language preferences (Accept-Language header); currently ~60 languages supported
  • id : links to persistant resources contain a unique (within the resources media type) identifier which can be used for client side optimiziations (resource caching) or business logic (enabling app specific features where users have done something with those places within the app before)

Question: Why id? Isn't the href the id?

  • href is representing an actionable request, id identifies the resource

  • href for the same resource might not be unique, as the URI also contains application (flow) state

  • the id is not intended to be used for URI templating (although experience has shown that developers do it)

  • `method' : HTTP method for hypermedia links using other methods that GET

  • accept : for PUT/POST methods the URN of the supported media types expected in the request body

  • `labels' : for PUT/POST methods that expect to contain data entered by a user in some form, this dictionary contains localized labels / selection values for form elements.

Special links types and other things not going by the book:

  • Some links for special link-relation types don't use the generic link object, but just a simple URL:
    • next : links to the next page within paginateable collections
    • icon : links to an iconic represenation for a given object
  • Some URL are not generic hypermedia links, but developers see them as part of the content
    • view : a URL that can be used to share a resource between users (e.g. via email); when the user then opens that URL we will receive a UI with the best available representation of the resource for the given device platform
    • */src : the URL of binary media elements (images)
  • Although the API encourages developers to use the appropriate HTTP headers, some client platforms only have limited access to those headers (e.g. JSONP). In order to support those clients, the API allows adding HTTP header also als query-string parameters to the hyperlinks; although kind of ugly, this has some nice side effects:
    • for demonstration purposes we can show every API behavior in any regular browser without need for special tools to manipulate HTTP headers (?accept=application/json for showing raw json representation in a browser)
    • users can easily send us reports of any unexpected behaviour with a single URL, that is easy to embedd in any message container (IM, email, jira...) and immediatly actionable for the API developers.
  • Various resource support different representation flavors, that allow app developers to adjust the content (and its size) to their needs. Developers can chose those flavors by adding additional representation modifiers as query string parameters to the href of the link object.
    • Example: address is in html, but not all clients support html and need a plain text representaion of rich text elements
    • So clients can append a param tf (text format) to the object href and get the address rendered in plain text, for instance
    • Response is still a JSON, only the value of some attributes non contains plain text instead of html snippets

Question: Shouldn't that be conveyed in the accept header? Extension to the content type

  • We have a hard time to convince developers to use different media types
  • JSONP was a requirement.

Question: deviating from HATEOAS, from the developer perspective this seems more confusing? Links, params, href, etc.

  • But it's easier to consume (easier to support a new param than parsing a bunch of links and picking the right one)
  • It seems like a lot of people in the room are coming from the API server/backend perspective, presenter is had to take client-side demands into account

The API IS the primary documentation

  • Without HATEOAS developers would get data, go to a documentation, and figure out how to build the next request
  • With HATEOAS developers learn what are the available next actions
  • Simple content negotiation can make the API when called from within a browser becomes a rich developer experience:
    • HTML serialization of json objects with extended functionality
    • linking json media type URN to corresponding sections in the reference documentation
    • simple form elements allow developers to learn/play with entry point request parameters and representation modifiers

Iteration on API design

  • In the beginning the API was more "academic", but application developers felt it was painful to consume

  • Noticed developers enjoyed playing around with the HATEOAS apis to learn, but once it was time to code they fell back to fixed object models/URIs

    • Don't have the right tools available for consuming HATEOAS apis?
  • They had many sessions with ~20 different teams, they didn't care about links and semantic types!

    • There's no tooling for it
    • They also offer SDKs in c++, hard/expensive to parse semantic info

Question: What tooling is missing?

  • Client side: support for something like JSON Schema link objects
  • Jsonary is a showcase how this might work

Additional questions / discussions

  • Inline JSON Schema in the response, or link to it?

    • Would be referenced from the content-type header, then clients can fetch and cache it
    • A lot of concerns related to the size of responses (again, re mobile clients)
  • Question: What kind of semantic markup would you add to the JSON to make it more identifiable?

    • The rel attribute for instance is not present there
    • JSON format by itself doesn't handle links, there are extensions to the media type to support it
  • Netflix had a big HATEOAS api, now going for device-specific APIs

  • Clients need to understand the object types, eg what is a urn:nlp-types:place?

    • Introduced a nightmare: they told developers to always check the type, and ignore link objects when they didn't know it
    • Whenever clients saw a new type they freaked out
    • Is this because there was no content negotiation?
      • If they're having a hard time to convince clients about different types, pushing content negotiation would be really hard
    • One idea they had was to introduce noisy data into their API so developers are forced to respect different types/constraints
      • Like chaos monkey for APIs
  • href includes a binary context so they can do things like change the relevance of results

    • Like a google analytics cookie instead of the URI space
    • When developers hardcode URIs they bypass this context
    • They're considering making every request start through some specific public endpoints
  • Why are developers not going for HATEOAS aware clients?

    • Pragmatism/urgency: they just want to get their stuff done
    • But that doesn't take into account the cost of maintaining this client over years
    • Some people are missing SOAP, better conventions to handle client specification and API changes
    • One idea to handle this is to take the Google approach, generate clients based off a JSON spec
  • They extend the API by adding new link object types

    • Clients broke for instance when they introduced a "did you mean?" type to search results
    • Again, they tell clients to ignore types they don't know
  • Some objects are dictionaries

    • Like contacts (label: phone, value: "(123) 456789" / label: email, value: [email protected] / etc)
  • Currently there's no way to fetch all type definitions from the API

    • There is a domain model and all documentation is generated off it, but they couldn't do that yet
    • Domain model is in Scala, gets rendered in different representations
  • How do we classify this API in relation to HATEOAS?

    • This is a hybrid/there is tight coupling between concepts, etc.
      • How? All his resources are provided in the responses?
        • Because of ids and URL patterns. Client must fill template URIs with ids
    • Someone invested 4 months to get a proper client written to their HATEOAS api
  • Filling ids in URI templates is harder than picking a URL from a list rendered by the API

    • But in practice there's still an effort into picking the right link
    • Say the API has 700 links for relevant information
  • What's the example of the perfect HATEOAS API?

    • Hard question - there are two examples in Steve Klabnik's blog
    • Twilio
    • GitHub is close
    • But all of them with reservations
    • This is a cutting edge concept, they are being made at the moment

Clone this wiki locally