Share and Discuss Hypermedia API Entry Point

I would like to share and discuss what I call the hypermedia API entry point document. JSON API does not explicitly standardize this but it is the initial document that a client application uses to discover all the available resource collections which to me are the root level API’s if you will. The URL to this entry point document is the only URL any client application needs to know as further hypermedia is discovered at runtime by following “rels” in the links or relationships of resources with the availability of the links or relationships being dependent on the state of the resource, HATEOAS etc.

Because there is no standard for this as far as I know, every API development team will develop something similar in concept but have a different implementation if you will. I will share a condensed version of an API entry point document we use in production where we and multiple third party companies integrate against.

Quick background, at the core of our hypermedia API is the purchase of movie tickets. Culture is important to us meaning depending on the client application culture choice our hypermedia will try and return “culture sensitive” attributes in the culture of choice of the client application if possible. Our decision was to have culture be a part of the URL of the REST API with the main rationale being for caching purposes where we use the URL as cache keys and the cached value is a JSON API document with translations for the respective culture. I know another solution is to put the culture request in the HTTP header but to me was pragmatic to be a part of the URL. Another decision was to have the major REST API version be a part of the URL as well. I know another solution is to put the version in the HTTP header but to me was pragmatic to be a part of the URL.

For our API entry point, we put all hypermedia in the links object of the API entry point resource. The other choice was in the relationships and I debated between the two. In the end for this version of our REST API, I choose the links object for reasons of aesthetics, simplicity, and honestly the API entry point is represented as a resource but it is a “special” resource and having relationships to all the resource collections at the time didn’t seem correct - I don’t think there is a right or wrong answer here and I could be convinced otherwise.

Because of culture, our API entry point document is actually read in two GET requests. The first GET request our REST API returns the API entry point document with the links object containing rels by the respective ISO culture name. The client application will find the desired culture hypermedia link by ISO name and do a second GET request of the API entry point document for the respective culture. The API entry point document links object contains all resource collection links with culture baked into the URL strings of the respective links. Because the API entry point document is very static we do return respective caching headers in the HTTP responses telling the client application to cache the API entry point documents for a “long time” so in my opinion performance of 2 GET requests is negligible.

The following are the API entry point documents condensed for this thread:

API Entry Point Document - Before Culture Choice

{
  "links": {
	"self": "https://dev.api.movietickets.com:443/v2"
  },
  "data": {
	"type": "api-entry-point",
	"attributes": {
	  "message": "Entry point into the MovieTickets REST API.",
	  "api-version": {
		"major-number": 2,
		"minor-number": 1,
		"build-number": 251
	  },
	  "website": "http://www.movietickets.com",
	  "mobile-website": "http://mobile.movietickets.com"
	},
	"links": {
	  "self": "https://dev.api.movietickets.com:443/v2",
	  "en-us": "https://dev.api.movietickets.com:443/v2/en-us",
	  "es-us": "https://dev.api.movietickets.com:443/v2/es-us",
	  "es-ar": "https://dev.api.movietickets.com:443/v2/es-ar",
	  "en-ca": "https://dev.api.movietickets.com:443/v2/en-ca",
	  "fr-ca": "https://dev.api.movietickets.com:443/v2/fr-ca",
	  "en-gb": "https://dev.api.movietickets.com:443/v2/en-gb",
	  "es-cl": "https://dev.api.movietickets.com:443/v2/es-cl",
	  "es-co": "https://dev.api.movietickets.com:443/v2/es-co",
	  "es-do": "https://dev.api.movietickets.com:443/v2/es-do",
	  "es-es": "https://dev.api.movietickets.com:443/v2/es-es",
	  "es-mx": "https://dev.api.movietickets.com:443/v2/es-mx"
	}
  }
}

API Entry Point Document - After Culture Choice

{
  "links": {
    "up": "https://dev.api.movietickets.com:443/v2",
    "self": "https://dev.api.movietickets.com:443/v2/en-us"
  },
  "data": {
    "type": "api-entry-point",
    "attributes": {
      "message": "Entry point into the MovieTickets REST API.",
      "api-version": {
        "major-number": 2,
        "minor-number": 1,
        "build-number": 251
      },
      "website": "http://www.movietickets.com",
      "mobile-website": "http://mobile.movietickets.com"
    },
    "links": {
      "self": "https://dev.api.movietickets.com:443/v2/en-us",
      ...
      "affiliates": "https://dev.api.movietickets.com:443/v2/en-us/affiliates",
      "auditoriums": "https://dev.api.movietickets.com:443/v2/en-us/auditoriums",
      ...
      "box-offices": "https://dev.api.movietickets.com:443/v2/en-us/box-offices",
      "box-offices-latest": "https://dev.api.movietickets.com:443/v2/en-us/box-offices/latest",
      ...
      "customers": "https://dev.api.movietickets.com:443/v2/en-us/customers",
      ...
      "movies": "https://dev.api.movietickets.com:443/v2/en-us/movies",
      "movies-coming-soon": "https://dev.api.movietickets.com:443/v2/en-us/movies/coming-soon",
      "movies-now-playing": "https://dev.api.movietickets.com:443/v2/en-us/movies/now-playing",
      ...
      "orders": "https://dev.api.movietickets.com:443/v2/en-us/orders",
      "performances": "https://dev.api.movietickets.com:443/v2/en-us/performances",
      "theaters": "https://dev.api.movietickets.com:443/v2/en-us/theaters",
      ...
      "ticketing-trends": "https://dev.api.movietickets.com:443/v2/en-us/ticketing-trends",
      "ticketing-trends-latest": "https://dev.api.movietickets.com:443/v2/en-us/ticketing-trends/latest",
      ...
    }
  }
}

Any comments or questions feel free to ask. I would be curious to see what other API development teams did for their respective hypermedia API entry point documents.

Should there be a JSON API standard for the API entry point document?

What would be your suggestions for standardizing a JSON API entry point document?

Gulp Here goes.
JSON Api is a media type format, not a protocol. There are a few decisions like the articulated URI patterns which make it far less than ideal for a hypermedia web api.

The very most JSON Api could include within the ‘home document’ or API entry point as you call it should be a list of the resources as if they were relationships. Your option works with the links object because you have created a resource to be related to the primary data object. The problem with using relationships is it would violate the required structure, as you wouldn’t want them available at /(?/)relationships/relationshipName as they are required to be. This is really constraining, and entirely unnecessary with HATEOAS, but it was added for backwards familiarity to the rails community who were going to consume this format through Ember.js.

Earlier in my research into hypermedia APIs I came to this forum with the explicit goal to talk about the lack of a home document and semantic profile support in JSON Api, however as my research continued what I discovered is the format is pretty deeply flawed for use within a truly HATEOAS environment. I’ll paraphrase Steve Klabnik when he said JSON Api is not format he would have made if he was out to create the perfect hypermedia format.

It certainly can use HATEOAS but I don’t see a backwards compatible way to introduce a required home document format which can be dependably guaranteed for JSON Api clients, and without the guarantee good hypermedia clients are going to be rarely built or utilized. The ideal solution is therefor to introduce JSON Home or some similar format, NOT to add something the functionality in JSON Api.

For some more in depth guidelines I’ve put together on hypermedia web APIs you can check out my series here.

Regarding the API you have for movietickets.com, it seems you’ve run aground of many of the problems caused by the un-opinionated nature of JSON Api towards hypermedia. Your API demonstrates quite completely the problem with adding hypermedia controls to a CRUD or path driven web API proto-format. The driving design constraints are not strictly orthogonal, but they are at rather opposing extremes of the spectrum. Restating my previous point, it isn’t that JSON Api can’t have hypermedia controls done well, it’s that it doesn’t guarantee them. Without the guarantee, the intent to drive state via hypermedia will make the consumption of a true HATEOAS JSON Api service a bother, rather than a boon. The format is not truly capable of complete HATEOAS, as it requires certain semi-stateful information to be managed via the URI patterns as you have noted.

That’s my… well can’t call it $0.02 cause it seems rather long… maybe my $0.45?